blob: f701c031132305ebbb62aab1487096a91fc3b060 [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_RegExpCloneResult(Arguments args) {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001428 ASSERT(args.length() == 1);
1429 Map* regexp_result_map;
1430 {
1431 AssertNoAllocation no_gc;
1432 HandleScope handles;
1433 regexp_result_map = Top::global_context()->regexp_result_map();
1434 }
1435 if (!args[0]->IsJSArray()) return args[0];
1436
1437 JSArray* result = JSArray::cast(args[0]);
1438 // Arguments to RegExpCloneResult should always be fresh RegExp exec call
1439 // results (either a fresh JSRegExpResult or null).
1440 // If the argument is not a JSRegExpResult, or isn't unmodified, just return
1441 // the argument uncloned.
1442 if (result->map() != regexp_result_map) return result;
1443
1444 // Having the original JSRegExpResult map guarantees that we have
1445 // fast elements and no properties except the two in-object properties.
1446 ASSERT(result->HasFastElements());
1447 ASSERT(result->properties() == Heap::empty_fixed_array());
1448 ASSERT_EQ(2, regexp_result_map->inobject_properties());
1449
lrn@chromium.org303ada72010-10-27 09:33:13 +00001450 Object* new_array_alloc;
1451 { MaybeObject* maybe_new_array_alloc =
1452 Heap::AllocateRaw(JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
1453 if (!maybe_new_array_alloc->ToObject(&new_array_alloc)) {
1454 return maybe_new_array_alloc;
1455 }
1456 }
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001457
1458 // Set HeapObject map to JSRegExpResult map.
1459 reinterpret_cast<HeapObject*>(new_array_alloc)->set_map(regexp_result_map);
1460
1461 JSArray* new_array = JSArray::cast(new_array_alloc);
1462
1463 // Copy JSObject properties.
1464 new_array->set_properties(result->properties()); // Empty FixedArray.
1465
1466 // Copy JSObject elements as copy-on-write.
1467 FixedArray* elements = FixedArray::cast(result->elements());
1468 if (elements != Heap::empty_fixed_array()) {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001469 elements->set_map(Heap::fixed_cow_array_map());
1470 }
1471 new_array->set_elements(elements);
1472
1473 // Copy JSArray length.
1474 new_array->set_length(result->length());
1475
1476 // Copy JSRegExpResult in-object property fields input and index.
1477 new_array->FastPropertyAtPut(JSRegExpResult::kIndexIndex,
1478 result->FastPropertyAt(
1479 JSRegExpResult::kIndexIndex));
1480 new_array->FastPropertyAtPut(JSRegExpResult::kInputIndex,
1481 result->FastPropertyAt(
1482 JSRegExpResult::kInputIndex));
1483 return new_array;
1484}
1485
1486
lrn@chromium.org303ada72010-10-27 09:33:13 +00001487static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001488 AssertNoAllocation no_alloc;
1489 ASSERT(args.length() == 5);
1490 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1491 CONVERT_CHECKED(String, source, args[1]);
1492
1493 Object* global = args[2];
1494 if (!global->IsTrue()) global = Heap::false_value();
1495
1496 Object* ignoreCase = args[3];
1497 if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value();
1498
1499 Object* multiline = args[4];
1500 if (!multiline->IsTrue()) multiline = Heap::false_value();
1501
1502 Map* map = regexp->map();
1503 Object* constructor = map->constructor();
1504 if (constructor->IsJSFunction() &&
1505 JSFunction::cast(constructor)->initial_map() == map) {
1506 // If we still have the original map, set in-object properties directly.
1507 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1508 // TODO(lrn): Consider skipping write barrier on booleans as well.
1509 // Both true and false should be in oldspace at all times.
1510 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1511 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1512 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1513 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1514 Smi::FromInt(0),
1515 SKIP_WRITE_BARRIER);
1516 return regexp;
1517 }
1518
lrn@chromium.org303ada72010-10-27 09:33:13 +00001519 // Map has changed, so use generic, but slower, method. Since these
1520 // properties were all added as DONT_DELETE they must be present and
1521 // normal so no failures can be expected.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001522 PropertyAttributes final =
1523 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1524 PropertyAttributes writable =
1525 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001526 MaybeObject* result;
1527 result = regexp->IgnoreAttributesAndSetLocalProperty(Heap::source_symbol(),
1528 source,
1529 final);
1530 ASSERT(!result->IsFailure());
1531 result = regexp->IgnoreAttributesAndSetLocalProperty(Heap::global_symbol(),
1532 global,
1533 final);
1534 ASSERT(!result->IsFailure());
1535 result =
1536 regexp->IgnoreAttributesAndSetLocalProperty(Heap::ignore_case_symbol(),
1537 ignoreCase,
1538 final);
1539 ASSERT(!result->IsFailure());
1540 result = regexp->IgnoreAttributesAndSetLocalProperty(Heap::multiline_symbol(),
1541 multiline,
1542 final);
1543 ASSERT(!result->IsFailure());
1544 result =
1545 regexp->IgnoreAttributesAndSetLocalProperty(Heap::last_index_symbol(),
1546 Smi::FromInt(0),
1547 writable);
1548 ASSERT(!result->IsFailure());
1549 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001550 return regexp;
1551}
1552
1553
lrn@chromium.org303ada72010-10-27 09:33:13 +00001554static MaybeObject* Runtime_FinishArrayPrototypeSetup(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001555 HandleScope scope;
1556 ASSERT(args.length() == 1);
1557 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1558 // This is necessary to enable fast checks for absence of elements
1559 // on Array.prototype and below.
1560 prototype->set_elements(Heap::empty_fixed_array());
1561 return Smi::FromInt(0);
1562}
1563
1564
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001565static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
1566 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001567 Builtins::Name builtin_name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001568 Handle<String> key = Factory::LookupAsciiSymbol(name);
1569 Handle<Code> code(Builtins::builtin(builtin_name));
1570 Handle<JSFunction> optimized = Factory::NewFunction(key,
1571 JS_OBJECT_TYPE,
1572 JSObject::kHeaderSize,
1573 code,
1574 false);
1575 optimized->shared()->DontAdaptArguments();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001576 SetProperty(holder, key, optimized, NONE);
1577 return optimized;
1578}
1579
1580
lrn@chromium.org303ada72010-10-27 09:33:13 +00001581static MaybeObject* Runtime_SpecialArrayFunctions(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001582 HandleScope scope;
1583 ASSERT(args.length() == 1);
1584 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1585
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001586 InstallBuiltin(holder, "pop", Builtins::ArrayPop);
1587 InstallBuiltin(holder, "push", Builtins::ArrayPush);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001588 InstallBuiltin(holder, "shift", Builtins::ArrayShift);
1589 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
1590 InstallBuiltin(holder, "slice", Builtins::ArraySlice);
1591 InstallBuiltin(holder, "splice", Builtins::ArraySplice);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001592 InstallBuiltin(holder, "concat", Builtins::ArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001593
1594 return *holder;
1595}
1596
1597
lrn@chromium.org303ada72010-10-27 09:33:13 +00001598static MaybeObject* Runtime_GetGlobalReceiver(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001599 // Returns a real global receiver, not one of builtins object.
1600 Context* global_context = Top::context()->global()->global_context();
1601 return global_context->global()->global_receiver();
1602}
1603
1604
lrn@chromium.org303ada72010-10-27 09:33:13 +00001605static MaybeObject* Runtime_MaterializeRegExpLiteral(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001606 HandleScope scope;
1607 ASSERT(args.length() == 4);
1608 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1609 int index = Smi::cast(args[1])->value();
1610 Handle<String> pattern = args.at<String>(2);
1611 Handle<String> flags = args.at<String>(3);
1612
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001613 // Get the RegExp function from the context in the literals array.
1614 // This is the RegExp function from the context in which the
1615 // function was created. We do not use the RegExp function from the
1616 // current global context because this might be the RegExp function
1617 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001618 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001619 Handle<JSFunction>(
1620 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001621 // Compute the regular expression literal.
1622 bool has_pending_exception;
1623 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001624 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1625 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001626 if (has_pending_exception) {
1627 ASSERT(Top::has_pending_exception());
1628 return Failure::Exception();
1629 }
1630 literals->set(index, *regexp);
1631 return *regexp;
1632}
1633
1634
lrn@chromium.org303ada72010-10-27 09:33:13 +00001635static MaybeObject* Runtime_FunctionGetName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001636 NoHandleAllocation ha;
1637 ASSERT(args.length() == 1);
1638
1639 CONVERT_CHECKED(JSFunction, f, args[0]);
1640 return f->shared()->name();
1641}
1642
1643
lrn@chromium.org303ada72010-10-27 09:33:13 +00001644static MaybeObject* Runtime_FunctionSetName(Arguments args) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001645 NoHandleAllocation ha;
1646 ASSERT(args.length() == 2);
1647
1648 CONVERT_CHECKED(JSFunction, f, args[0]);
1649 CONVERT_CHECKED(String, name, args[1]);
1650 f->shared()->set_name(name);
1651 return Heap::undefined_value();
1652}
1653
1654
lrn@chromium.org303ada72010-10-27 09:33:13 +00001655static MaybeObject* Runtime_FunctionRemovePrototype(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001656 NoHandleAllocation ha;
1657 ASSERT(args.length() == 1);
1658
1659 CONVERT_CHECKED(JSFunction, f, args[0]);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001660 Object* obj;
1661 { MaybeObject* maybe_obj = f->RemovePrototype();
1662 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1663 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001664
1665 return Heap::undefined_value();
1666}
1667
1668
lrn@chromium.org303ada72010-10-27 09:33:13 +00001669static MaybeObject* Runtime_FunctionGetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001670 HandleScope scope;
1671 ASSERT(args.length() == 1);
1672
1673 CONVERT_CHECKED(JSFunction, fun, args[0]);
1674 Handle<Object> script = Handle<Object>(fun->shared()->script());
1675 if (!script->IsScript()) return Heap::undefined_value();
1676
1677 return *GetScriptWrapper(Handle<Script>::cast(script));
1678}
1679
1680
lrn@chromium.org303ada72010-10-27 09:33:13 +00001681static MaybeObject* Runtime_FunctionGetSourceCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001682 NoHandleAllocation ha;
1683 ASSERT(args.length() == 1);
1684
1685 CONVERT_CHECKED(JSFunction, f, args[0]);
1686 return f->shared()->GetSourceCode();
1687}
1688
1689
lrn@chromium.org303ada72010-10-27 09:33:13 +00001690static MaybeObject* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001691 NoHandleAllocation ha;
1692 ASSERT(args.length() == 1);
1693
1694 CONVERT_CHECKED(JSFunction, fun, args[0]);
1695 int pos = fun->shared()->start_position();
1696 return Smi::FromInt(pos);
1697}
1698
1699
lrn@chromium.org303ada72010-10-27 09:33:13 +00001700static MaybeObject* Runtime_FunctionGetPositionForOffset(Arguments args) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001701 ASSERT(args.length() == 2);
1702
1703 CONVERT_CHECKED(JSFunction, fun, args[0]);
1704 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1705
1706 Code* code = fun->code();
1707 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1708
1709 Address pc = code->address() + offset;
1710 return Smi::FromInt(fun->code()->SourcePosition(pc));
1711}
1712
1713
1714
lrn@chromium.org303ada72010-10-27 09:33:13 +00001715static MaybeObject* Runtime_FunctionSetInstanceClassName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001716 NoHandleAllocation ha;
1717 ASSERT(args.length() == 2);
1718
1719 CONVERT_CHECKED(JSFunction, fun, args[0]);
1720 CONVERT_CHECKED(String, name, args[1]);
1721 fun->SetInstanceClassName(name);
1722 return Heap::undefined_value();
1723}
1724
1725
lrn@chromium.org303ada72010-10-27 09:33:13 +00001726static MaybeObject* Runtime_FunctionSetLength(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001727 NoHandleAllocation ha;
1728 ASSERT(args.length() == 2);
1729
1730 CONVERT_CHECKED(JSFunction, fun, args[0]);
1731 CONVERT_CHECKED(Smi, length, args[1]);
1732 fun->shared()->set_length(length->value());
1733 return length;
1734}
1735
1736
lrn@chromium.org303ada72010-10-27 09:33:13 +00001737static MaybeObject* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001738 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001739 ASSERT(args.length() == 2);
1740
1741 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001742 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001743 Object* obj;
1744 { MaybeObject* maybe_obj =
1745 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1746 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1747 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001748 return args[0]; // return TOS
1749}
1750
1751
lrn@chromium.org303ada72010-10-27 09:33:13 +00001752static MaybeObject* Runtime_FunctionIsAPIFunction(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001753 NoHandleAllocation ha;
1754 ASSERT(args.length() == 1);
1755
1756 CONVERT_CHECKED(JSFunction, f, args[0]);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001757 return f->shared()->IsApiFunction() ? Heap::true_value()
1758 : Heap::false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001759}
1760
lrn@chromium.org303ada72010-10-27 09:33:13 +00001761static MaybeObject* Runtime_FunctionIsBuiltin(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001762 NoHandleAllocation ha;
1763 ASSERT(args.length() == 1);
1764
1765 CONVERT_CHECKED(JSFunction, f, args[0]);
1766 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
1767}
1768
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001769
lrn@chromium.org303ada72010-10-27 09:33:13 +00001770static MaybeObject* Runtime_SetCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001771 HandleScope scope;
1772 ASSERT(args.length() == 2);
1773
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001774 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001775 Handle<Object> code = args.at<Object>(1);
1776
1777 Handle<Context> context(target->context());
1778
1779 if (!code->IsNull()) {
1780 RUNTIME_ASSERT(code->IsJSFunction());
1781 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001782 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001783
1784 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001785 return Failure::Exception();
1786 }
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001787 // Set the code, scope info, formal parameter count,
1788 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001789 target->shared()->set_code(shared->code());
1790 target->set_code(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001791 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001792 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001793 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001794 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001795 // Set the source code of the target function to undefined.
1796 // SetCode is only used for built-in constructors like String,
1797 // Array, and Object, and some web code
1798 // doesn't like seeing source code for constructors.
1799 target->shared()->set_script(Heap::undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001800 // Clear the optimization hints related to the compiled code as these are no
1801 // longer valid when the code is overwritten.
1802 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001803 context = Handle<Context>(fun->context());
1804
1805 // Make sure we get a fresh copy of the literal vector to avoid
1806 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001807 int number_of_literals = fun->NumberOfLiterals();
1808 Handle<FixedArray> literals =
1809 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001810 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001811 // Insert the object, regexp and array functions in the literals
1812 // array prefix. These are the functions that will be used when
1813 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001814 literals->set(JSFunction::kLiteralGlobalContextIndex,
1815 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001816 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001817 // It's okay to skip the write barrier here because the literals
1818 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001819 target->set_literals(*literals, SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001820 }
1821
1822 target->set_context(*context);
1823 return *target;
1824}
1825
1826
lrn@chromium.org303ada72010-10-27 09:33:13 +00001827static MaybeObject* Runtime_SetExpectedNumberOfProperties(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001828 HandleScope scope;
1829 ASSERT(args.length() == 2);
1830 CONVERT_ARG_CHECKED(JSFunction, function, 0);
1831 CONVERT_SMI_CHECKED(num, args[1]);
1832 RUNTIME_ASSERT(num >= 0);
1833 SetExpectedNofProperties(function, num);
1834 return Heap::undefined_value();
1835}
1836
1837
lrn@chromium.org303ada72010-10-27 09:33:13 +00001838MUST_USE_RESULT static MaybeObject* CharFromCode(Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001839 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001840 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001841 if (code <= 0xffff) {
1842 return Heap::LookupSingleCharacterStringFromCode(code);
1843 }
1844 }
1845 return Heap::empty_string();
1846}
1847
1848
lrn@chromium.org303ada72010-10-27 09:33:13 +00001849static MaybeObject* Runtime_StringCharCodeAt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001850 NoHandleAllocation ha;
1851 ASSERT(args.length() == 2);
1852
1853 CONVERT_CHECKED(String, subject, args[0]);
1854 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001855 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001856
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001857 uint32_t i = 0;
1858 if (index->IsSmi()) {
1859 int value = Smi::cast(index)->value();
1860 if (value < 0) return Heap::nan_value();
1861 i = value;
1862 } else {
1863 ASSERT(index->IsHeapNumber());
1864 double value = HeapNumber::cast(index)->value();
1865 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00001866 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001867
1868 // Flatten the string. If someone wants to get a char at an index
1869 // in a cons string, it is likely that more indices will be
1870 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001871 Object* flat;
1872 { MaybeObject* maybe_flat = subject->TryFlatten();
1873 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
1874 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001875 subject = String::cast(flat);
1876
1877 if (i >= static_cast<uint32_t>(subject->length())) {
1878 return Heap::nan_value();
1879 }
1880
1881 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001882}
1883
1884
lrn@chromium.org303ada72010-10-27 09:33:13 +00001885static MaybeObject* Runtime_CharFromCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001886 NoHandleAllocation ha;
1887 ASSERT(args.length() == 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001888 return CharFromCode(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001889}
1890
lrn@chromium.org25156de2010-04-06 13:10:27 +00001891
1892class FixedArrayBuilder {
1893 public:
1894 explicit FixedArrayBuilder(int initial_capacity)
1895 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
1896 length_(0) {
1897 // Require a non-zero initial size. Ensures that doubling the size to
1898 // extend the array will work.
1899 ASSERT(initial_capacity > 0);
1900 }
1901
1902 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
1903 : array_(backing_store),
1904 length_(0) {
1905 // Require a non-zero initial size. Ensures that doubling the size to
1906 // extend the array will work.
1907 ASSERT(backing_store->length() > 0);
1908 }
1909
1910 bool HasCapacity(int elements) {
1911 int length = array_->length();
1912 int required_length = length_ + elements;
1913 return (length >= required_length);
1914 }
1915
1916 void EnsureCapacity(int elements) {
1917 int length = array_->length();
1918 int required_length = length_ + elements;
1919 if (length < required_length) {
1920 int new_length = length;
1921 do {
1922 new_length *= 2;
1923 } while (new_length < required_length);
1924 Handle<FixedArray> extended_array =
1925 Factory::NewFixedArrayWithHoles(new_length);
1926 array_->CopyTo(0, *extended_array, 0, length_);
1927 array_ = extended_array;
1928 }
1929 }
1930
1931 void Add(Object* value) {
1932 ASSERT(length_ < capacity());
1933 array_->set(length_, value);
1934 length_++;
1935 }
1936
1937 void Add(Smi* value) {
1938 ASSERT(length_ < capacity());
1939 array_->set(length_, value);
1940 length_++;
1941 }
1942
1943 Handle<FixedArray> array() {
1944 return array_;
1945 }
1946
1947 int length() {
1948 return length_;
1949 }
1950
1951 int capacity() {
1952 return array_->length();
1953 }
1954
1955 Handle<JSArray> ToJSArray() {
1956 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
1957 result_array->set_length(Smi::FromInt(length_));
1958 return result_array;
1959 }
1960
1961 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
1962 target_array->set_elements(*array_);
1963 target_array->set_length(Smi::FromInt(length_));
1964 return target_array;
1965 }
1966
1967 private:
1968 Handle<FixedArray> array_;
1969 int length_;
1970};
1971
1972
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001973// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001974const int kStringBuilderConcatHelperLengthBits = 11;
1975const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001976
1977template <typename schar>
1978static inline void StringBuilderConcatHelper(String*,
1979 schar*,
1980 FixedArray*,
1981 int);
1982
lrn@chromium.org25156de2010-04-06 13:10:27 +00001983typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
1984 StringBuilderSubstringLength;
1985typedef BitField<int,
1986 kStringBuilderConcatHelperLengthBits,
1987 kStringBuilderConcatHelperPositionBits>
1988 StringBuilderSubstringPosition;
1989
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001990
1991class ReplacementStringBuilder {
1992 public:
1993 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
lrn@chromium.org25156de2010-04-06 13:10:27 +00001994 : array_builder_(estimated_part_count),
1995 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001996 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00001997 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001998 // Require a non-zero initial size. Ensures that doubling the size to
1999 // extend the array will work.
2000 ASSERT(estimated_part_count > 0);
2001 }
2002
lrn@chromium.org25156de2010-04-06 13:10:27 +00002003 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2004 int from,
2005 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002006 ASSERT(from >= 0);
2007 int length = to - from;
2008 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002009 if (StringBuilderSubstringLength::is_valid(length) &&
2010 StringBuilderSubstringPosition::is_valid(from)) {
2011 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2012 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002013 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002014 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002015 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002016 builder->Add(Smi::FromInt(-length));
2017 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002018 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002019 }
2020
2021
2022 void EnsureCapacity(int elements) {
2023 array_builder_.EnsureCapacity(elements);
2024 }
2025
2026
2027 void AddSubjectSlice(int from, int to) {
2028 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002029 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002030 }
2031
2032
2033 void AddString(Handle<String> string) {
2034 int length = string->length();
2035 ASSERT(length > 0);
2036 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002037 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002038 is_ascii_ = false;
2039 }
2040 IncrementCharacterCount(length);
2041 }
2042
2043
2044 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002045 if (array_builder_.length() == 0) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002046 return Factory::empty_string();
2047 }
2048
2049 Handle<String> joined_string;
2050 if (is_ascii_) {
2051 joined_string = NewRawAsciiString(character_count_);
2052 AssertNoAllocation no_alloc;
2053 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2054 char* char_buffer = seq->GetChars();
2055 StringBuilderConcatHelper(*subject_,
2056 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002057 *array_builder_.array(),
2058 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002059 } else {
2060 // Non-ASCII.
2061 joined_string = NewRawTwoByteString(character_count_);
2062 AssertNoAllocation no_alloc;
2063 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2064 uc16* char_buffer = seq->GetChars();
2065 StringBuilderConcatHelper(*subject_,
2066 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002067 *array_builder_.array(),
2068 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002069 }
2070 return joined_string;
2071 }
2072
2073
2074 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002075 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002076 V8::FatalProcessOutOfMemory("String.replace result too large.");
2077 }
2078 character_count_ += by;
2079 }
2080
lrn@chromium.org25156de2010-04-06 13:10:27 +00002081 Handle<JSArray> GetParts() {
2082 Handle<JSArray> result =
2083 Factory::NewJSArrayWithElements(array_builder_.array());
2084 result->set_length(Smi::FromInt(array_builder_.length()));
2085 return result;
2086 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002087
lrn@chromium.org25156de2010-04-06 13:10:27 +00002088 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002089 Handle<String> NewRawAsciiString(int size) {
2090 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
2091 }
2092
2093
2094 Handle<String> NewRawTwoByteString(int size) {
2095 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
2096 }
2097
2098
2099 void AddElement(Object* element) {
2100 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002101 ASSERT(array_builder_.capacity() > array_builder_.length());
2102 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002103 }
2104
lrn@chromium.org25156de2010-04-06 13:10:27 +00002105 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002106 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002107 int character_count_;
2108 bool is_ascii_;
2109};
2110
2111
2112class CompiledReplacement {
2113 public:
2114 CompiledReplacement()
2115 : parts_(1), replacement_substrings_(0) {}
2116
2117 void Compile(Handle<String> replacement,
2118 int capture_count,
2119 int subject_length);
2120
2121 void Apply(ReplacementStringBuilder* builder,
2122 int match_from,
2123 int match_to,
2124 Handle<JSArray> last_match_info);
2125
2126 // Number of distinct parts of the replacement pattern.
2127 int parts() {
2128 return parts_.length();
2129 }
2130 private:
2131 enum PartType {
2132 SUBJECT_PREFIX = 1,
2133 SUBJECT_SUFFIX,
2134 SUBJECT_CAPTURE,
2135 REPLACEMENT_SUBSTRING,
2136 REPLACEMENT_STRING,
2137
2138 NUMBER_OF_PART_TYPES
2139 };
2140
2141 struct ReplacementPart {
2142 static inline ReplacementPart SubjectMatch() {
2143 return ReplacementPart(SUBJECT_CAPTURE, 0);
2144 }
2145 static inline ReplacementPart SubjectCapture(int capture_index) {
2146 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2147 }
2148 static inline ReplacementPart SubjectPrefix() {
2149 return ReplacementPart(SUBJECT_PREFIX, 0);
2150 }
2151 static inline ReplacementPart SubjectSuffix(int subject_length) {
2152 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2153 }
2154 static inline ReplacementPart ReplacementString() {
2155 return ReplacementPart(REPLACEMENT_STRING, 0);
2156 }
2157 static inline ReplacementPart ReplacementSubString(int from, int to) {
2158 ASSERT(from >= 0);
2159 ASSERT(to > from);
2160 return ReplacementPart(-from, to);
2161 }
2162
2163 // If tag <= 0 then it is the negation of a start index of a substring of
2164 // the replacement pattern, otherwise it's a value from PartType.
2165 ReplacementPart(int tag, int data)
2166 : tag(tag), data(data) {
2167 // Must be non-positive or a PartType value.
2168 ASSERT(tag < NUMBER_OF_PART_TYPES);
2169 }
2170 // Either a value of PartType or a non-positive number that is
2171 // the negation of an index into the replacement string.
2172 int tag;
2173 // The data value's interpretation depends on the value of tag:
2174 // tag == SUBJECT_PREFIX ||
2175 // tag == SUBJECT_SUFFIX: data is unused.
2176 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2177 // tag == REPLACEMENT_SUBSTRING ||
2178 // tag == REPLACEMENT_STRING: data is index into array of substrings
2179 // of the replacement string.
2180 // tag <= 0: Temporary representation of the substring of the replacement
2181 // string ranging over -tag .. data.
2182 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2183 // substring objects.
2184 int data;
2185 };
2186
2187 template<typename Char>
2188 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2189 Vector<Char> characters,
2190 int capture_count,
2191 int subject_length) {
2192 int length = characters.length();
2193 int last = 0;
2194 for (int i = 0; i < length; i++) {
2195 Char c = characters[i];
2196 if (c == '$') {
2197 int next_index = i + 1;
2198 if (next_index == length) { // No next character!
2199 break;
2200 }
2201 Char c2 = characters[next_index];
2202 switch (c2) {
2203 case '$':
2204 if (i > last) {
2205 // There is a substring before. Include the first "$".
2206 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2207 last = next_index + 1; // Continue after the second "$".
2208 } else {
2209 // Let the next substring start with the second "$".
2210 last = next_index;
2211 }
2212 i = next_index;
2213 break;
2214 case '`':
2215 if (i > last) {
2216 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2217 }
2218 parts->Add(ReplacementPart::SubjectPrefix());
2219 i = next_index;
2220 last = i + 1;
2221 break;
2222 case '\'':
2223 if (i > last) {
2224 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2225 }
2226 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2227 i = next_index;
2228 last = i + 1;
2229 break;
2230 case '&':
2231 if (i > last) {
2232 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2233 }
2234 parts->Add(ReplacementPart::SubjectMatch());
2235 i = next_index;
2236 last = i + 1;
2237 break;
2238 case '0':
2239 case '1':
2240 case '2':
2241 case '3':
2242 case '4':
2243 case '5':
2244 case '6':
2245 case '7':
2246 case '8':
2247 case '9': {
2248 int capture_ref = c2 - '0';
2249 if (capture_ref > capture_count) {
2250 i = next_index;
2251 continue;
2252 }
2253 int second_digit_index = next_index + 1;
2254 if (second_digit_index < length) {
2255 // Peek ahead to see if we have two digits.
2256 Char c3 = characters[second_digit_index];
2257 if ('0' <= c3 && c3 <= '9') { // Double digits.
2258 int double_digit_ref = capture_ref * 10 + c3 - '0';
2259 if (double_digit_ref <= capture_count) {
2260 next_index = second_digit_index;
2261 capture_ref = double_digit_ref;
2262 }
2263 }
2264 }
2265 if (capture_ref > 0) {
2266 if (i > last) {
2267 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2268 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002269 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002270 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2271 last = next_index + 1;
2272 }
2273 i = next_index;
2274 break;
2275 }
2276 default:
2277 i = next_index;
2278 break;
2279 }
2280 }
2281 }
2282 if (length > last) {
2283 if (last == 0) {
2284 parts->Add(ReplacementPart::ReplacementString());
2285 } else {
2286 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2287 }
2288 }
2289 }
2290
2291 ZoneList<ReplacementPart> parts_;
2292 ZoneList<Handle<String> > replacement_substrings_;
2293};
2294
2295
2296void CompiledReplacement::Compile(Handle<String> replacement,
2297 int capture_count,
2298 int subject_length) {
2299 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002300 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002301 AssertNoAllocation no_alloc;
2302 ParseReplacementPattern(&parts_,
2303 replacement->ToAsciiVector(),
2304 capture_count,
2305 subject_length);
2306 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002307 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002308 AssertNoAllocation no_alloc;
2309
2310 ParseReplacementPattern(&parts_,
2311 replacement->ToUC16Vector(),
2312 capture_count,
2313 subject_length);
2314 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002315 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002316 int substring_index = 0;
2317 for (int i = 0, n = parts_.length(); i < n; i++) {
2318 int tag = parts_[i].tag;
2319 if (tag <= 0) { // A replacement string slice.
2320 int from = -tag;
2321 int to = parts_[i].data;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002322 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002323 parts_[i].tag = REPLACEMENT_SUBSTRING;
2324 parts_[i].data = substring_index;
2325 substring_index++;
2326 } else if (tag == REPLACEMENT_STRING) {
2327 replacement_substrings_.Add(replacement);
2328 parts_[i].data = substring_index;
2329 substring_index++;
2330 }
2331 }
2332}
2333
2334
2335void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2336 int match_from,
2337 int match_to,
2338 Handle<JSArray> last_match_info) {
2339 for (int i = 0, n = parts_.length(); i < n; i++) {
2340 ReplacementPart part = parts_[i];
2341 switch (part.tag) {
2342 case SUBJECT_PREFIX:
2343 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2344 break;
2345 case SUBJECT_SUFFIX: {
2346 int subject_length = part.data;
2347 if (match_to < subject_length) {
2348 builder->AddSubjectSlice(match_to, subject_length);
2349 }
2350 break;
2351 }
2352 case SUBJECT_CAPTURE: {
2353 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002354 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002355 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2356 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2357 if (from >= 0 && to > from) {
2358 builder->AddSubjectSlice(from, to);
2359 }
2360 break;
2361 }
2362 case REPLACEMENT_SUBSTRING:
2363 case REPLACEMENT_STRING:
2364 builder->AddString(replacement_substrings_[part.data]);
2365 break;
2366 default:
2367 UNREACHABLE();
2368 }
2369 }
2370}
2371
2372
2373
lrn@chromium.org303ada72010-10-27 09:33:13 +00002374MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
2375 String* subject,
2376 JSRegExp* regexp,
2377 String* replacement,
2378 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002379 ASSERT(subject->IsFlat());
2380 ASSERT(replacement->IsFlat());
2381
2382 HandleScope handles;
2383
2384 int length = subject->length();
2385 Handle<String> subject_handle(subject);
2386 Handle<JSRegExp> regexp_handle(regexp);
2387 Handle<String> replacement_handle(replacement);
2388 Handle<JSArray> last_match_info_handle(last_match_info);
2389 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2390 subject_handle,
2391 0,
2392 last_match_info_handle);
2393 if (match.is_null()) {
2394 return Failure::Exception();
2395 }
2396 if (match->IsNull()) {
2397 return *subject_handle;
2398 }
2399
2400 int capture_count = regexp_handle->CaptureCount();
2401
2402 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002403 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002404 CompiledReplacement compiled_replacement;
2405 compiled_replacement.Compile(replacement_handle,
2406 capture_count,
2407 length);
2408
2409 bool is_global = regexp_handle->GetFlags().is_global();
2410
2411 // Guessing the number of parts that the final result string is built
2412 // from. Global regexps can match any number of times, so we guess
2413 // conservatively.
2414 int expected_parts =
2415 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
2416 ReplacementStringBuilder builder(subject_handle, expected_parts);
2417
2418 // Index of end of last match.
2419 int prev = 0;
2420
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002421 // Number of parts added by compiled replacement plus preceeding
2422 // string and possibly suffix after last match. It is possible for
2423 // all components to use two elements when encoded as two smis.
2424 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002425 bool matched = true;
2426 do {
2427 ASSERT(last_match_info_handle->HasFastElements());
2428 // Increase the capacity of the builder before entering local handle-scope,
2429 // so its internal buffer can safely allocate a new handle if it grows.
2430 builder.EnsureCapacity(parts_added_per_loop);
2431
2432 HandleScope loop_scope;
2433 int start, end;
2434 {
2435 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002436 FixedArray* match_info_array =
2437 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002438
2439 ASSERT_EQ(capture_count * 2 + 2,
2440 RegExpImpl::GetLastCaptureCount(match_info_array));
2441 start = RegExpImpl::GetCapture(match_info_array, 0);
2442 end = RegExpImpl::GetCapture(match_info_array, 1);
2443 }
2444
2445 if (prev < start) {
2446 builder.AddSubjectSlice(prev, start);
2447 }
2448 compiled_replacement.Apply(&builder,
2449 start,
2450 end,
2451 last_match_info_handle);
2452 prev = end;
2453
2454 // Only continue checking for global regexps.
2455 if (!is_global) break;
2456
2457 // Continue from where the match ended, unless it was an empty match.
2458 int next = end;
2459 if (start == end) {
2460 next = end + 1;
2461 if (next > length) break;
2462 }
2463
2464 match = RegExpImpl::Exec(regexp_handle,
2465 subject_handle,
2466 next,
2467 last_match_info_handle);
2468 if (match.is_null()) {
2469 return Failure::Exception();
2470 }
2471 matched = !match->IsNull();
2472 } while (matched);
2473
2474 if (prev < length) {
2475 builder.AddSubjectSlice(prev, length);
2476 }
2477
2478 return *(builder.ToString());
2479}
2480
2481
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002482template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002483MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
2484 String* subject,
2485 JSRegExp* regexp,
2486 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002487 ASSERT(subject->IsFlat());
2488
2489 HandleScope handles;
2490
2491 Handle<String> subject_handle(subject);
2492 Handle<JSRegExp> regexp_handle(regexp);
2493 Handle<JSArray> last_match_info_handle(last_match_info);
2494 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2495 subject_handle,
2496 0,
2497 last_match_info_handle);
2498 if (match.is_null()) return Failure::Exception();
2499 if (match->IsNull()) return *subject_handle;
2500
2501 ASSERT(last_match_info_handle->HasFastElements());
2502
2503 HandleScope loop_scope;
2504 int start, end;
2505 {
2506 AssertNoAllocation match_info_array_is_not_in_a_handle;
2507 FixedArray* match_info_array =
2508 FixedArray::cast(last_match_info_handle->elements());
2509
2510 start = RegExpImpl::GetCapture(match_info_array, 0);
2511 end = RegExpImpl::GetCapture(match_info_array, 1);
2512 }
2513
2514 int length = subject->length();
2515 int new_length = length - (end - start);
2516 if (new_length == 0) {
2517 return Heap::empty_string();
2518 }
2519 Handle<ResultSeqString> answer;
2520 if (ResultSeqString::kHasAsciiEncoding) {
2521 answer =
2522 Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
2523 } else {
2524 answer =
2525 Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
2526 }
2527
2528 // If the regexp isn't global, only match once.
2529 if (!regexp_handle->GetFlags().is_global()) {
2530 if (start > 0) {
2531 String::WriteToFlat(*subject_handle,
2532 answer->GetChars(),
2533 0,
2534 start);
2535 }
2536 if (end < length) {
2537 String::WriteToFlat(*subject_handle,
2538 answer->GetChars() + start,
2539 end,
2540 length);
2541 }
2542 return *answer;
2543 }
2544
2545 int prev = 0; // Index of end of last match.
2546 int next = 0; // Start of next search (prev unless last match was empty).
2547 int position = 0;
2548
2549 do {
2550 if (prev < start) {
2551 // Add substring subject[prev;start] to answer string.
2552 String::WriteToFlat(*subject_handle,
2553 answer->GetChars() + position,
2554 prev,
2555 start);
2556 position += start - prev;
2557 }
2558 prev = end;
2559 next = end;
2560 // Continue from where the match ended, unless it was an empty match.
2561 if (start == end) {
2562 next++;
2563 if (next > length) break;
2564 }
2565 match = RegExpImpl::Exec(regexp_handle,
2566 subject_handle,
2567 next,
2568 last_match_info_handle);
2569 if (match.is_null()) return Failure::Exception();
2570 if (match->IsNull()) break;
2571
2572 ASSERT(last_match_info_handle->HasFastElements());
2573 HandleScope loop_scope;
2574 {
2575 AssertNoAllocation match_info_array_is_not_in_a_handle;
2576 FixedArray* match_info_array =
2577 FixedArray::cast(last_match_info_handle->elements());
2578 start = RegExpImpl::GetCapture(match_info_array, 0);
2579 end = RegExpImpl::GetCapture(match_info_array, 1);
2580 }
2581 } while (true);
2582
2583 if (prev < length) {
2584 // Add substring subject[prev;length] to answer string.
2585 String::WriteToFlat(*subject_handle,
2586 answer->GetChars() + position,
2587 prev,
2588 length);
2589 position += length - prev;
2590 }
2591
2592 if (position == 0) {
2593 return Heap::empty_string();
2594 }
2595
2596 // Shorten string and fill
2597 int string_size = ResultSeqString::SizeFor(position);
2598 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2599 int delta = allocated_string_size - string_size;
2600
2601 answer->set_length(position);
2602 if (delta == 0) return *answer;
2603
2604 Address end_of_string = answer->address() + string_size;
2605 Heap::CreateFillerObjectAt(end_of_string, delta);
2606
2607 return *answer;
2608}
2609
2610
lrn@chromium.org303ada72010-10-27 09:33:13 +00002611static MaybeObject* Runtime_StringReplaceRegExpWithString(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002612 ASSERT(args.length() == 4);
2613
2614 CONVERT_CHECKED(String, subject, args[0]);
2615 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002616 Object* flat_subject;
2617 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2618 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2619 return maybe_flat_subject;
2620 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002621 }
2622 subject = String::cast(flat_subject);
2623 }
2624
2625 CONVERT_CHECKED(String, replacement, args[2]);
2626 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002627 Object* flat_replacement;
2628 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2629 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2630 return maybe_flat_replacement;
2631 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002632 }
2633 replacement = String::cast(flat_replacement);
2634 }
2635
2636 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2637 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2638
2639 ASSERT(last_match_info->HasFastElements());
2640
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002641 if (replacement->length() == 0) {
2642 if (subject->HasOnlyAsciiChars()) {
2643 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
2644 subject, regexp, last_match_info);
2645 } else {
2646 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
2647 subject, regexp, last_match_info);
2648 }
2649 }
2650
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002651 return StringReplaceRegExpWithString(subject,
2652 regexp,
2653 replacement,
2654 last_match_info);
2655}
2656
2657
ager@chromium.org7c537e22008-10-16 08:43:32 +00002658// Perform string match of pattern on subject, starting at start index.
2659// Caller must ensure that 0 <= start_index <= sub->length(),
2660// and should check that pat->length() + start_index <= sub->length()
2661int Runtime::StringMatch(Handle<String> sub,
2662 Handle<String> pat,
2663 int start_index) {
2664 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002665 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002666
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002667 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002668 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002669
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002670 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002671 if (start_index + pattern_length > subject_length) return -1;
2672
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002673 if (!sub->IsFlat()) FlattenString(sub);
2674 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002675
ager@chromium.org7c537e22008-10-16 08:43:32 +00002676 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002677 // Extract flattened substrings of cons strings before determining asciiness.
2678 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002679 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002680 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002681 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002682
ager@chromium.org7c537e22008-10-16 08:43:32 +00002683 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002684 if (seq_pat->IsAsciiRepresentation()) {
2685 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2686 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002687 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002688 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002689 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002690 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002691 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2692 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002693 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002694 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002695 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002696}
2697
2698
lrn@chromium.org303ada72010-10-27 09:33:13 +00002699static MaybeObject* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002700 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002701 ASSERT(args.length() == 3);
2702
ager@chromium.org7c537e22008-10-16 08:43:32 +00002703 CONVERT_ARG_CHECKED(String, sub, 0);
2704 CONVERT_ARG_CHECKED(String, pat, 1);
2705
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002706 Object* index = args[2];
2707 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002708 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002709
ager@chromium.org870a0b62008-11-04 11:43:05 +00002710 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002711 int position = Runtime::StringMatch(sub, pat, start_index);
2712 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002713}
2714
2715
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002716template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002717static int StringMatchBackwards(Vector<const schar> subject,
2718 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002719 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002720 int pattern_length = pattern.length();
2721 ASSERT(pattern_length >= 1);
2722 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002723
2724 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002725 for (int i = 0; i < pattern_length; i++) {
2726 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002727 if (c > String::kMaxAsciiCharCode) {
2728 return -1;
2729 }
2730 }
2731 }
2732
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002733 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002734 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002735 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002736 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002737 while (j < pattern_length) {
2738 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002739 break;
2740 }
2741 j++;
2742 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002743 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002744 return i;
2745 }
2746 }
2747 return -1;
2748}
2749
lrn@chromium.org303ada72010-10-27 09:33:13 +00002750static MaybeObject* Runtime_StringLastIndexOf(Arguments args) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002751 HandleScope scope; // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002752 ASSERT(args.length() == 3);
2753
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002754 CONVERT_ARG_CHECKED(String, sub, 0);
2755 CONVERT_ARG_CHECKED(String, pat, 1);
2756
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002757 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002758 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002759 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002760
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002761 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002762 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002763
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002764 if (start_index + pat_length > sub_length) {
2765 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002766 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002767
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002768 if (pat_length == 0) {
2769 return Smi::FromInt(start_index);
2770 }
2771
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002772 if (!sub->IsFlat()) FlattenString(sub);
2773 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002774
2775 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2776
2777 int position = -1;
2778
2779 if (pat->IsAsciiRepresentation()) {
2780 Vector<const char> pat_vector = pat->ToAsciiVector();
2781 if (sub->IsAsciiRepresentation()) {
2782 position = StringMatchBackwards(sub->ToAsciiVector(),
2783 pat_vector,
2784 start_index);
2785 } else {
2786 position = StringMatchBackwards(sub->ToUC16Vector(),
2787 pat_vector,
2788 start_index);
2789 }
2790 } else {
2791 Vector<const uc16> pat_vector = pat->ToUC16Vector();
2792 if (sub->IsAsciiRepresentation()) {
2793 position = StringMatchBackwards(sub->ToAsciiVector(),
2794 pat_vector,
2795 start_index);
2796 } else {
2797 position = StringMatchBackwards(sub->ToUC16Vector(),
2798 pat_vector,
2799 start_index);
2800 }
2801 }
2802
2803 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002804}
2805
2806
lrn@chromium.org303ada72010-10-27 09:33:13 +00002807static MaybeObject* Runtime_StringLocaleCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002808 NoHandleAllocation ha;
2809 ASSERT(args.length() == 2);
2810
2811 CONVERT_CHECKED(String, str1, args[0]);
2812 CONVERT_CHECKED(String, str2, args[1]);
2813
2814 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002815 int str1_length = str1->length();
2816 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002817
2818 // Decide trivial cases without flattening.
2819 if (str1_length == 0) {
2820 if (str2_length == 0) return Smi::FromInt(0); // Equal.
2821 return Smi::FromInt(-str2_length);
2822 } else {
2823 if (str2_length == 0) return Smi::FromInt(str1_length);
2824 }
2825
2826 int end = str1_length < str2_length ? str1_length : str2_length;
2827
2828 // No need to flatten if we are going to find the answer on the first
2829 // character. At this point we know there is at least one character
2830 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002831 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002832 if (d != 0) return Smi::FromInt(d);
2833
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002834 str1->TryFlatten();
2835 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002836
2837 static StringInputBuffer buf1;
2838 static StringInputBuffer buf2;
2839
2840 buf1.Reset(str1);
2841 buf2.Reset(str2);
2842
2843 for (int i = 0; i < end; i++) {
2844 uint16_t char1 = buf1.GetNext();
2845 uint16_t char2 = buf2.GetNext();
2846 if (char1 != char2) return Smi::FromInt(char1 - char2);
2847 }
2848
2849 return Smi::FromInt(str1_length - str2_length);
2850}
2851
2852
lrn@chromium.org303ada72010-10-27 09:33:13 +00002853static MaybeObject* Runtime_SubString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002854 NoHandleAllocation ha;
2855 ASSERT(args.length() == 3);
2856
2857 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002858 Object* from = args[1];
2859 Object* to = args[2];
2860 int start, end;
2861 // We have a fast integer-only case here to avoid a conversion to double in
2862 // the common case where from and to are Smis.
2863 if (from->IsSmi() && to->IsSmi()) {
2864 start = Smi::cast(from)->value();
2865 end = Smi::cast(to)->value();
2866 } else {
2867 CONVERT_DOUBLE_CHECKED(from_number, from);
2868 CONVERT_DOUBLE_CHECKED(to_number, to);
2869 start = FastD2I(from_number);
2870 end = FastD2I(to_number);
2871 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002872 RUNTIME_ASSERT(end >= start);
2873 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002874 RUNTIME_ASSERT(end <= value->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002875 Counters::sub_string_runtime.Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002876 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002877}
2878
2879
lrn@chromium.org303ada72010-10-27 09:33:13 +00002880static MaybeObject* Runtime_StringMatch(Arguments args) {
ager@chromium.org41826e72009-03-30 13:30:57 +00002881 ASSERT_EQ(3, args.length());
2882
2883 CONVERT_ARG_CHECKED(String, subject, 0);
2884 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
2885 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
2886 HandleScope handles;
2887
2888 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
2889
2890 if (match.is_null()) {
2891 return Failure::Exception();
2892 }
2893 if (match->IsNull()) {
2894 return Heap::null_value();
2895 }
2896 int length = subject->length();
2897
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002898 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00002899 ZoneList<int> offsets(8);
2900 do {
2901 int start;
2902 int end;
2903 {
2904 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002905 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00002906 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
2907 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
2908 }
2909 offsets.Add(start);
2910 offsets.Add(end);
2911 int index = start < end ? end : end + 1;
2912 if (index > length) break;
2913 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
2914 if (match.is_null()) {
2915 return Failure::Exception();
2916 }
2917 } while (!match->IsNull());
2918 int matches = offsets.length() / 2;
2919 Handle<FixedArray> elements = Factory::NewFixedArray(matches);
2920 for (int i = 0; i < matches ; i++) {
2921 int from = offsets.at(i * 2);
2922 int to = offsets.at(i * 2 + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002923 Handle<String> match = Factory::NewSubString(subject, from, to);
2924 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00002925 }
2926 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
2927 result->set_length(Smi::FromInt(matches));
2928 return *result;
2929}
2930
2931
lrn@chromium.org25156de2010-04-06 13:10:27 +00002932// Two smis before and after the match, for very long strings.
2933const int kMaxBuilderEntriesPerRegExpMatch = 5;
2934
2935
2936static void SetLastMatchInfoNoCaptures(Handle<String> subject,
2937 Handle<JSArray> last_match_info,
2938 int match_start,
2939 int match_end) {
2940 // Fill last_match_info with a single capture.
2941 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
2942 AssertNoAllocation no_gc;
2943 FixedArray* elements = FixedArray::cast(last_match_info->elements());
2944 RegExpImpl::SetLastCaptureCount(elements, 2);
2945 RegExpImpl::SetLastInput(elements, *subject);
2946 RegExpImpl::SetLastSubject(elements, *subject);
2947 RegExpImpl::SetCapture(elements, 0, match_start);
2948 RegExpImpl::SetCapture(elements, 1, match_end);
2949}
2950
2951
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002952template <typename SubjectChar, typename PatternChar>
2953static bool SearchStringMultiple(Vector<const SubjectChar> subject,
2954 Vector<const PatternChar> pattern,
2955 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002956 FixedArrayBuilder* builder,
2957 int* match_pos) {
2958 int pos = *match_pos;
2959 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002960 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002961 int max_search_start = subject_length - pattern_length;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002962 StringSearch<PatternChar, SubjectChar> search(pattern);
2963 while (pos <= max_search_start) {
2964 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
2965 *match_pos = pos;
2966 return false;
2967 }
2968 // Position of end of previous match.
2969 int match_end = pos + pattern_length;
2970 int new_pos = search.Search(subject, match_end);
2971 if (new_pos >= 0) {
2972 // A match.
2973 if (new_pos > match_end) {
2974 ReplacementStringBuilder::AddSubjectSlice(builder,
2975 match_end,
2976 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002977 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002978 pos = new_pos;
2979 builder->Add(pattern_string);
2980 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002981 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002982 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002983 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002984
lrn@chromium.org25156de2010-04-06 13:10:27 +00002985 if (pos < max_search_start) {
2986 ReplacementStringBuilder::AddSubjectSlice(builder,
2987 pos + pattern_length,
2988 subject_length);
2989 }
2990 *match_pos = pos;
2991 return true;
2992}
2993
2994
2995static bool SearchStringMultiple(Handle<String> subject,
2996 Handle<String> pattern,
2997 Handle<JSArray> last_match_info,
2998 FixedArrayBuilder* builder) {
2999 ASSERT(subject->IsFlat());
3000 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003001
3002 // Treating as if a previous match was before first character.
3003 int match_pos = -pattern->length();
3004
3005 for (;;) { // Break when search complete.
3006 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3007 AssertNoAllocation no_gc;
3008 if (subject->IsAsciiRepresentation()) {
3009 Vector<const char> subject_vector = subject->ToAsciiVector();
3010 if (pattern->IsAsciiRepresentation()) {
3011 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003012 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003013 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003014 builder,
3015 &match_pos)) break;
3016 } else {
3017 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003018 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003019 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003020 builder,
3021 &match_pos)) break;
3022 }
3023 } else {
3024 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3025 if (pattern->IsAsciiRepresentation()) {
3026 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003027 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003028 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003029 builder,
3030 &match_pos)) break;
3031 } else {
3032 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003033 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003034 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003035 builder,
3036 &match_pos)) break;
3037 }
3038 }
3039 }
3040
3041 if (match_pos >= 0) {
3042 SetLastMatchInfoNoCaptures(subject,
3043 last_match_info,
3044 match_pos,
3045 match_pos + pattern->length());
3046 return true;
3047 }
3048 return false; // No matches at all.
3049}
3050
3051
3052static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
3053 Handle<String> subject,
3054 Handle<JSRegExp> regexp,
3055 Handle<JSArray> last_match_array,
3056 FixedArrayBuilder* builder) {
3057 ASSERT(subject->IsFlat());
3058 int match_start = -1;
3059 int match_end = 0;
3060 int pos = 0;
3061 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3062 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3063
3064 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003065 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003066 int subject_length = subject->length();
3067
3068 for (;;) { // Break on failure, return on exception.
3069 RegExpImpl::IrregexpResult result =
3070 RegExpImpl::IrregexpExecOnce(regexp,
3071 subject,
3072 pos,
3073 register_vector);
3074 if (result == RegExpImpl::RE_SUCCESS) {
3075 match_start = register_vector[0];
3076 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3077 if (match_end < match_start) {
3078 ReplacementStringBuilder::AddSubjectSlice(builder,
3079 match_end,
3080 match_start);
3081 }
3082 match_end = register_vector[1];
3083 HandleScope loop_scope;
3084 builder->Add(*Factory::NewSubString(subject, match_start, match_end));
3085 if (match_start != match_end) {
3086 pos = match_end;
3087 } else {
3088 pos = match_end + 1;
3089 if (pos > subject_length) break;
3090 }
3091 } else if (result == RegExpImpl::RE_FAILURE) {
3092 break;
3093 } else {
3094 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3095 return result;
3096 }
3097 }
3098
3099 if (match_start >= 0) {
3100 if (match_end < subject_length) {
3101 ReplacementStringBuilder::AddSubjectSlice(builder,
3102 match_end,
3103 subject_length);
3104 }
3105 SetLastMatchInfoNoCaptures(subject,
3106 last_match_array,
3107 match_start,
3108 match_end);
3109 return RegExpImpl::RE_SUCCESS;
3110 } else {
3111 return RegExpImpl::RE_FAILURE; // No matches at all.
3112 }
3113}
3114
3115
3116static RegExpImpl::IrregexpResult SearchRegExpMultiple(
3117 Handle<String> subject,
3118 Handle<JSRegExp> regexp,
3119 Handle<JSArray> last_match_array,
3120 FixedArrayBuilder* builder) {
3121
3122 ASSERT(subject->IsFlat());
3123 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3124 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3125
3126 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003127 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003128
3129 RegExpImpl::IrregexpResult result =
3130 RegExpImpl::IrregexpExecOnce(regexp,
3131 subject,
3132 0,
3133 register_vector);
3134
3135 int capture_count = regexp->CaptureCount();
3136 int subject_length = subject->length();
3137
3138 // Position to search from.
3139 int pos = 0;
3140 // End of previous match. Differs from pos if match was empty.
3141 int match_end = 0;
3142 if (result == RegExpImpl::RE_SUCCESS) {
3143 // Need to keep a copy of the previous match for creating last_match_info
3144 // at the end, so we have two vectors that we swap between.
3145 OffsetsVector registers2(required_registers);
3146 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3147
3148 do {
3149 int match_start = register_vector[0];
3150 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3151 if (match_end < match_start) {
3152 ReplacementStringBuilder::AddSubjectSlice(builder,
3153 match_end,
3154 match_start);
3155 }
3156 match_end = register_vector[1];
3157
3158 {
3159 // Avoid accumulating new handles inside loop.
3160 HandleScope temp_scope;
3161 // Arguments array to replace function is match, captures, index and
3162 // subject, i.e., 3 + capture count in total.
3163 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003164 Handle<String> match = Factory::NewSubString(subject,
3165 match_start,
3166 match_end);
3167 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003168 for (int i = 1; i <= capture_count; i++) {
3169 int start = register_vector[i * 2];
3170 if (start >= 0) {
3171 int end = register_vector[i * 2 + 1];
3172 ASSERT(start <= end);
3173 Handle<String> substring = Factory::NewSubString(subject,
3174 start,
3175 end);
3176 elements->set(i, *substring);
3177 } else {
3178 ASSERT(register_vector[i * 2 + 1] < 0);
3179 elements->set(i, Heap::undefined_value());
3180 }
3181 }
3182 elements->set(capture_count + 1, Smi::FromInt(match_start));
3183 elements->set(capture_count + 2, *subject);
3184 builder->Add(*Factory::NewJSArrayWithElements(elements));
3185 }
3186 // Swap register vectors, so the last successful match is in
3187 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003188 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003189 prev_register_vector = register_vector;
3190 register_vector = tmp;
3191
3192 if (match_end > match_start) {
3193 pos = match_end;
3194 } else {
3195 pos = match_end + 1;
3196 if (pos > subject_length) {
3197 break;
3198 }
3199 }
3200
3201 result = RegExpImpl::IrregexpExecOnce(regexp,
3202 subject,
3203 pos,
3204 register_vector);
3205 } while (result == RegExpImpl::RE_SUCCESS);
3206
3207 if (result != RegExpImpl::RE_EXCEPTION) {
3208 // Finished matching, with at least one match.
3209 if (match_end < subject_length) {
3210 ReplacementStringBuilder::AddSubjectSlice(builder,
3211 match_end,
3212 subject_length);
3213 }
3214
3215 int last_match_capture_count = (capture_count + 1) * 2;
3216 int last_match_array_size =
3217 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3218 last_match_array->EnsureSize(last_match_array_size);
3219 AssertNoAllocation no_gc;
3220 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3221 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3222 RegExpImpl::SetLastSubject(elements, *subject);
3223 RegExpImpl::SetLastInput(elements, *subject);
3224 for (int i = 0; i < last_match_capture_count; i++) {
3225 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3226 }
3227 return RegExpImpl::RE_SUCCESS;
3228 }
3229 }
3230 // No matches at all, return failure or exception result directly.
3231 return result;
3232}
3233
3234
lrn@chromium.org303ada72010-10-27 09:33:13 +00003235static MaybeObject* Runtime_RegExpExecMultiple(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003236 ASSERT(args.length() == 4);
3237 HandleScope handles;
3238
3239 CONVERT_ARG_CHECKED(String, subject, 1);
3240 if (!subject->IsFlat()) { FlattenString(subject); }
3241 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3242 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3243 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3244
3245 ASSERT(last_match_info->HasFastElements());
3246 ASSERT(regexp->GetFlags().is_global());
3247 Handle<FixedArray> result_elements;
3248 if (result_array->HasFastElements()) {
3249 result_elements =
3250 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3251 } else {
3252 result_elements = Factory::NewFixedArrayWithHoles(16);
3253 }
3254 FixedArrayBuilder builder(result_elements);
3255
3256 if (regexp->TypeTag() == JSRegExp::ATOM) {
3257 Handle<String> pattern(
3258 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003259 if (!pattern->IsFlat()) FlattenString(pattern);
3260 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
3261 return *builder.ToJSArray(result_array);
3262 }
3263 return Heap::null_value();
3264 }
3265
3266 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3267
3268 RegExpImpl::IrregexpResult result;
3269 if (regexp->CaptureCount() == 0) {
3270 result = SearchRegExpNoCaptureMultiple(subject,
3271 regexp,
3272 last_match_info,
3273 &builder);
3274 } else {
3275 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
3276 }
3277 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
3278 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
3279 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3280 return Failure::Exception();
3281}
3282
3283
lrn@chromium.org303ada72010-10-27 09:33:13 +00003284static MaybeObject* Runtime_NumberToRadixString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003285 NoHandleAllocation ha;
3286 ASSERT(args.length() == 2);
3287
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003288 // Fast case where the result is a one character string.
3289 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3290 int value = Smi::cast(args[0])->value();
3291 int radix = Smi::cast(args[1])->value();
3292 if (value >= 0 && value < radix) {
3293 RUNTIME_ASSERT(radix <= 36);
3294 // Character array used for conversion.
3295 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
3296 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]);
3297 }
3298 }
3299
3300 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003301 CONVERT_DOUBLE_CHECKED(value, args[0]);
3302 if (isnan(value)) {
3303 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3304 }
3305 if (isinf(value)) {
3306 if (value < 0) {
3307 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3308 }
3309 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3310 }
3311 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3312 int radix = FastD2I(radix_number);
3313 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3314 char* str = DoubleToRadixCString(value, radix);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003315 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003316 DeleteArray(str);
3317 return result;
3318}
3319
3320
lrn@chromium.org303ada72010-10-27 09:33:13 +00003321static MaybeObject* Runtime_NumberToFixed(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003322 NoHandleAllocation ha;
3323 ASSERT(args.length() == 2);
3324
3325 CONVERT_DOUBLE_CHECKED(value, args[0]);
3326 if (isnan(value)) {
3327 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3328 }
3329 if (isinf(value)) {
3330 if (value < 0) {
3331 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3332 }
3333 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3334 }
3335 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3336 int f = FastD2I(f_number);
3337 RUNTIME_ASSERT(f >= 0);
3338 char* str = DoubleToFixedCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003339 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003340 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003341 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003342}
3343
3344
lrn@chromium.org303ada72010-10-27 09:33:13 +00003345static MaybeObject* Runtime_NumberToExponential(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003346 NoHandleAllocation ha;
3347 ASSERT(args.length() == 2);
3348
3349 CONVERT_DOUBLE_CHECKED(value, args[0]);
3350 if (isnan(value)) {
3351 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3352 }
3353 if (isinf(value)) {
3354 if (value < 0) {
3355 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3356 }
3357 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3358 }
3359 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3360 int f = FastD2I(f_number);
3361 RUNTIME_ASSERT(f >= -1 && f <= 20);
3362 char* str = DoubleToExponentialCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003363 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003364 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003365 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003366}
3367
3368
lrn@chromium.org303ada72010-10-27 09:33:13 +00003369static MaybeObject* Runtime_NumberToPrecision(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003370 NoHandleAllocation ha;
3371 ASSERT(args.length() == 2);
3372
3373 CONVERT_DOUBLE_CHECKED(value, args[0]);
3374 if (isnan(value)) {
3375 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3376 }
3377 if (isinf(value)) {
3378 if (value < 0) {
3379 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3380 }
3381 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3382 }
3383 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3384 int f = FastD2I(f_number);
3385 RUNTIME_ASSERT(f >= 1 && f <= 21);
3386 char* str = DoubleToPrecisionCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003387 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003388 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003389 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003390}
3391
3392
3393// Returns a single character string where first character equals
3394// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003395static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003396 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003397 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003398 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003399 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003400 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003401 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003402}
3403
3404
lrn@chromium.org303ada72010-10-27 09:33:13 +00003405MaybeObject* Runtime::GetElementOrCharAt(Handle<Object> object,
3406 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003407 // Handle [] indexing on Strings
3408 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003409 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3410 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003411 }
3412
3413 // Handle [] indexing on String objects
3414 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003415 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3416 Handle<Object> result =
3417 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3418 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003419 }
3420
3421 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003422 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003423 return prototype->GetElement(index);
3424 }
3425
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003426 return GetElement(object, index);
3427}
3428
3429
lrn@chromium.org303ada72010-10-27 09:33:13 +00003430MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003431 return object->GetElement(index);
3432}
3433
3434
lrn@chromium.org303ada72010-10-27 09:33:13 +00003435MaybeObject* Runtime::GetObjectProperty(Handle<Object> object,
3436 Handle<Object> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003437 HandleScope scope;
3438
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003439 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003440 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003441 Handle<Object> error =
3442 Factory::NewTypeError("non_object_property_load",
3443 HandleVector(args, 2));
3444 return Top::Throw(*error);
3445 }
3446
3447 // Check if the given key is an array index.
3448 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003449 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003450 return GetElementOrCharAt(object, index);
3451 }
3452
3453 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003454 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003455 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003456 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003457 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003458 bool has_pending_exception = false;
3459 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003460 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003461 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003462 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003463 }
3464
ager@chromium.org32912102009-01-16 10:38:43 +00003465 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003466 // the element if so.
3467 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003468 return GetElementOrCharAt(object, index);
3469 } else {
3470 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003471 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003472 }
3473}
3474
3475
lrn@chromium.org303ada72010-10-27 09:33:13 +00003476static MaybeObject* Runtime_GetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003477 NoHandleAllocation ha;
3478 ASSERT(args.length() == 2);
3479
3480 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003481 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003482
3483 return Runtime::GetObjectProperty(object, key);
3484}
3485
3486
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003487// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003488static MaybeObject* Runtime_KeyedGetProperty(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003489 NoHandleAllocation ha;
3490 ASSERT(args.length() == 2);
3491
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003492 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003493 // itself.
3494 //
3495 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003496 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003497 // global proxy object never has properties. This is the case
3498 // because the global proxy object forwards everything to its hidden
3499 // prototype including local lookups.
3500 //
3501 // Additionally, we need to make sure that we do not cache results
3502 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003503 if (args[0]->IsJSObject() &&
3504 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003505 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003506 args[1]->IsString()) {
3507 JSObject* receiver = JSObject::cast(args[0]);
3508 String* key = String::cast(args[1]);
3509 if (receiver->HasFastProperties()) {
3510 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003511 Map* receiver_map = receiver->map();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003512 int offset = KeyedLookupCache::Lookup(receiver_map, key);
3513 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003514 Object* value = receiver->FastPropertyAt(offset);
3515 return value->IsTheHole() ? Heap::undefined_value() : value;
3516 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003517 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003518 LookupResult result;
3519 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003520 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003521 int offset = result.GetFieldIndex();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003522 KeyedLookupCache::Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003523 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003524 }
3525 } else {
3526 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003527 StringDictionary* dictionary = receiver->property_dictionary();
3528 int entry = dictionary->FindEntry(key);
3529 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003530 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003531 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003532 if (!receiver->IsGlobalObject()) return value;
3533 value = JSGlobalPropertyCell::cast(value)->value();
3534 if (!value->IsTheHole()) return value;
3535 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003536 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003537 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003538 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3539 // Fast case for string indexing using [] with a smi index.
3540 HandleScope scope;
3541 Handle<String> str = args.at<String>(0);
3542 int index = Smi::cast(args[1])->value();
3543 Handle<Object> result = GetCharAt(str, index);
3544 return *result;
ager@chromium.org7c537e22008-10-16 08:43:32 +00003545 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003546
3547 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003548 return Runtime::GetObjectProperty(args.at<Object>(0),
3549 args.at<Object>(1));
3550}
3551
3552
lrn@chromium.org303ada72010-10-27 09:33:13 +00003553static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003554 ASSERT(args.length() == 5);
3555 HandleScope scope;
3556 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3557 CONVERT_CHECKED(String, name, args[1]);
3558 CONVERT_CHECKED(Smi, flag_setter, args[2]);
3559 CONVERT_CHECKED(JSFunction, fun, args[3]);
3560 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3561 int unchecked = flag_attr->value();
3562 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3563 RUNTIME_ASSERT(!obj->IsNull());
3564 LookupResult result;
3565 obj->LocalLookupRealNamedProperty(name, &result);
3566
3567 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3568 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3569 // delete it to avoid running into trouble in DefineAccessor, which
3570 // handles this incorrectly if the property is readonly (does nothing)
3571 if (result.IsProperty() &&
3572 (result.type() == FIELD || result.type() == NORMAL
3573 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003574 Object* ok;
3575 { MaybeObject* maybe_ok =
3576 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3577 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3578 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003579 }
3580 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3581}
3582
lrn@chromium.org303ada72010-10-27 09:33:13 +00003583static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003584 ASSERT(args.length() == 4);
3585 HandleScope scope;
3586 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3587 CONVERT_ARG_CHECKED(String, name, 1);
3588 Handle<Object> obj_value = args.at<Object>(2);
3589
3590 CONVERT_CHECKED(Smi, flag, args[3]);
3591 int unchecked = flag->value();
3592 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3593
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003594 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3595
3596 // Check if this is an element.
3597 uint32_t index;
3598 bool is_element = name->AsArrayIndex(&index);
3599
3600 // Special case for elements if any of the flags are true.
3601 // If elements are in fast case we always implicitly assume that:
3602 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3603 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3604 is_element) {
3605 // Normalize the elements to enable attributes on the property.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003606 NormalizeElements(js_object);
3607 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003608 // Make sure that we never go back to fast case.
3609 dictionary->set_requires_slow_elements();
3610 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003611 NumberDictionarySet(dictionary, index, obj_value, details);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003612 }
3613
ager@chromium.org5c838252010-02-19 08:53:10 +00003614 LookupResult result;
3615 js_object->LocalLookupRealNamedProperty(*name, &result);
3616
ager@chromium.org5c838252010-02-19 08:53:10 +00003617 // Take special care when attributes are different and there is already
3618 // a property. For simplicity we normalize the property which enables us
3619 // to not worry about changing the instance_descriptor and creating a new
3620 // map. The current version of SetObjectProperty does not handle attributes
3621 // correctly in the case where a property is a field and is reset with
3622 // new attributes.
3623 if (result.IsProperty() && attr != result.GetAttributes()) {
3624 // New attributes - normalize to avoid writing to instance descriptor
lrn@chromium.org303ada72010-10-27 09:33:13 +00003625 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003626 // Use IgnoreAttributes version since a readonly property may be
3627 // overridden and SetProperty does not allow this.
3628 return js_object->IgnoreAttributesAndSetLocalProperty(*name,
3629 *obj_value,
3630 attr);
3631 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003632
ager@chromium.org5c838252010-02-19 08:53:10 +00003633 return Runtime::SetObjectProperty(js_object, name, obj_value, attr);
3634}
3635
3636
lrn@chromium.org303ada72010-10-27 09:33:13 +00003637MaybeObject* Runtime::SetObjectProperty(Handle<Object> object,
3638 Handle<Object> key,
3639 Handle<Object> value,
3640 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003641 HandleScope scope;
3642
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003643 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003644 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003645 Handle<Object> error =
3646 Factory::NewTypeError("non_object_property_store",
3647 HandleVector(args, 2));
3648 return Top::Throw(*error);
3649 }
3650
3651 // If the object isn't a JavaScript object, we ignore the store.
3652 if (!object->IsJSObject()) return *value;
3653
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003654 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3655
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003656 // Check if the given key is an array index.
3657 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003658 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003659 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3660 // of a string using [] notation. We need to support this too in
3661 // JavaScript.
3662 // In the case of a String object we just need to redirect the assignment to
3663 // the underlying string if the index is in range. Since the underlying
3664 // string does nothing with the assignment then we can ignore such
3665 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003666 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003667 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003668 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003669
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003670 Handle<Object> result = SetElement(js_object, index, value);
3671 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003672 return *value;
3673 }
3674
3675 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003676 Handle<Object> result;
3677 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003678 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003679 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003680 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003681 key_string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003682 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003683 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003684 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003685 return *value;
3686 }
3687
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003688 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003689 bool has_pending_exception = false;
3690 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3691 if (has_pending_exception) return Failure::Exception();
3692 Handle<String> name = Handle<String>::cast(converted);
3693
3694 if (name->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003695 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003696 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003697 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003698 }
3699}
3700
3701
lrn@chromium.org303ada72010-10-27 09:33:13 +00003702MaybeObject* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
3703 Handle<Object> key,
3704 Handle<Object> value,
3705 PropertyAttributes attr) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003706 HandleScope scope;
3707
3708 // Check if the given key is an array index.
3709 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003710 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003711 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3712 // of a string using [] notation. We need to support this too in
3713 // JavaScript.
3714 // In the case of a String object we just need to redirect the assignment to
3715 // the underlying string if the index is in range. Since the underlying
3716 // string does nothing with the assignment then we can ignore such
3717 // assignments.
3718 if (js_object->IsStringObjectWithCharacterAt(index)) {
3719 return *value;
3720 }
3721
3722 return js_object->SetElement(index, *value);
3723 }
3724
3725 if (key->IsString()) {
3726 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003727 return js_object->SetElement(index, *value);
3728 } else {
3729 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003730 key_string->TryFlatten();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003731 return js_object->IgnoreAttributesAndSetLocalProperty(*key_string,
3732 *value,
3733 attr);
3734 }
3735 }
3736
3737 // Call-back into JavaScript to convert the key to a string.
3738 bool has_pending_exception = false;
3739 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3740 if (has_pending_exception) return Failure::Exception();
3741 Handle<String> name = Handle<String>::cast(converted);
3742
3743 if (name->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003744 return js_object->SetElement(index, *value);
3745 } else {
3746 return js_object->IgnoreAttributesAndSetLocalProperty(*name, *value, attr);
3747 }
3748}
3749
3750
lrn@chromium.org303ada72010-10-27 09:33:13 +00003751MaybeObject* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
3752 Handle<Object> key) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003753 HandleScope scope;
3754
3755 // Check if the given key is an array index.
3756 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003757 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003758 // In Firefox/SpiderMonkey, Safari and Opera you can access the
3759 // characters of a string using [] notation. In the case of a
3760 // String object we just need to redirect the deletion to the
3761 // underlying string if the index is in range. Since the
3762 // underlying string does nothing with the deletion, we can ignore
3763 // such deletions.
3764 if (js_object->IsStringObjectWithCharacterAt(index)) {
3765 return Heap::true_value();
3766 }
3767
3768 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
3769 }
3770
3771 Handle<String> key_string;
3772 if (key->IsString()) {
3773 key_string = Handle<String>::cast(key);
3774 } else {
3775 // Call-back into JavaScript to convert the key to a string.
3776 bool has_pending_exception = false;
3777 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3778 if (has_pending_exception) return Failure::Exception();
3779 key_string = Handle<String>::cast(converted);
3780 }
3781
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003782 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003783 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
3784}
3785
3786
lrn@chromium.org303ada72010-10-27 09:33:13 +00003787static MaybeObject* Runtime_SetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003788 NoHandleAllocation ha;
3789 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
3790
3791 Handle<Object> object = args.at<Object>(0);
3792 Handle<Object> key = args.at<Object>(1);
3793 Handle<Object> value = args.at<Object>(2);
3794
3795 // Compute attributes.
3796 PropertyAttributes attributes = NONE;
3797 if (args.length() == 4) {
3798 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003799 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003800 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003801 RUNTIME_ASSERT(
3802 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3803 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003804 }
3805 return Runtime::SetObjectProperty(object, key, value, attributes);
3806}
3807
3808
3809// Set a local property, even if it is READ_ONLY. If the property does not
3810// exist, it will be added with attributes NONE.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003811static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003812 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003813 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003814 CONVERT_CHECKED(JSObject, object, args[0]);
3815 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003816 // Compute attributes.
3817 PropertyAttributes attributes = NONE;
3818 if (args.length() == 4) {
3819 CONVERT_CHECKED(Smi, value_obj, args[3]);
3820 int unchecked_value = value_obj->value();
3821 // Only attribute bits should be set.
3822 RUNTIME_ASSERT(
3823 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3824 attributes = static_cast<PropertyAttributes>(unchecked_value);
3825 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003826
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003827 return object->
3828 IgnoreAttributesAndSetLocalProperty(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003829}
3830
3831
lrn@chromium.org303ada72010-10-27 09:33:13 +00003832static MaybeObject* Runtime_DeleteProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003833 NoHandleAllocation ha;
3834 ASSERT(args.length() == 2);
3835
3836 CONVERT_CHECKED(JSObject, object, args[0]);
3837 CONVERT_CHECKED(String, key, args[1]);
ager@chromium.orge2902be2009-06-08 12:21:35 +00003838 return object->DeleteProperty(key, JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003839}
3840
3841
ager@chromium.org9085a012009-05-11 19:22:57 +00003842static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
3843 Handle<String> key) {
3844 if (object->HasLocalProperty(*key)) return Heap::true_value();
3845 // Handle hidden prototypes. If there's a hidden prototype above this thing
3846 // then we have to check it for properties, because they are supposed to
3847 // look like they are on this object.
3848 Handle<Object> proto(object->GetPrototype());
3849 if (proto->IsJSObject() &&
3850 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
3851 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
3852 }
3853 return Heap::false_value();
3854}
3855
3856
lrn@chromium.org303ada72010-10-27 09:33:13 +00003857static MaybeObject* Runtime_HasLocalProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003858 NoHandleAllocation ha;
3859 ASSERT(args.length() == 2);
3860 CONVERT_CHECKED(String, key, args[1]);
3861
ager@chromium.org9085a012009-05-11 19:22:57 +00003862 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003863 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00003864 if (obj->IsJSObject()) {
3865 JSObject* object = JSObject::cast(obj);
3866 // Fast case - no interceptors.
3867 if (object->HasRealNamedProperty(key)) return Heap::true_value();
3868 // Slow case. Either it's not there or we have an interceptor. We should
3869 // have handles for this kind of deal.
3870 HandleScope scope;
3871 return HasLocalPropertyImplementation(Handle<JSObject>(object),
3872 Handle<String>(key));
3873 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003874 // Well, there is one exception: Handle [] on strings.
3875 uint32_t index;
3876 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00003877 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003878 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003879 return Heap::true_value();
3880 }
3881 }
3882 return Heap::false_value();
3883}
3884
3885
lrn@chromium.org303ada72010-10-27 09:33:13 +00003886static MaybeObject* Runtime_HasProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003887 NoHandleAllocation na;
3888 ASSERT(args.length() == 2);
3889
3890 // Only JS objects can have properties.
3891 if (args[0]->IsJSObject()) {
3892 JSObject* object = JSObject::cast(args[0]);
3893 CONVERT_CHECKED(String, key, args[1]);
3894 if (object->HasProperty(key)) return Heap::true_value();
3895 }
3896 return Heap::false_value();
3897}
3898
3899
lrn@chromium.org303ada72010-10-27 09:33:13 +00003900static MaybeObject* Runtime_HasElement(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003901 NoHandleAllocation na;
3902 ASSERT(args.length() == 2);
3903
3904 // Only JS objects can have elements.
3905 if (args[0]->IsJSObject()) {
3906 JSObject* object = JSObject::cast(args[0]);
3907 CONVERT_CHECKED(Smi, index_obj, args[1]);
3908 uint32_t index = index_obj->value();
3909 if (object->HasElement(index)) return Heap::true_value();
3910 }
3911 return Heap::false_value();
3912}
3913
3914
lrn@chromium.org303ada72010-10-27 09:33:13 +00003915static MaybeObject* Runtime_IsPropertyEnumerable(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003916 NoHandleAllocation ha;
3917 ASSERT(args.length() == 2);
3918
3919 CONVERT_CHECKED(JSObject, object, args[0]);
3920 CONVERT_CHECKED(String, key, args[1]);
3921
3922 uint32_t index;
3923 if (key->AsArrayIndex(&index)) {
3924 return Heap::ToBoolean(object->HasElement(index));
3925 }
3926
ager@chromium.org870a0b62008-11-04 11:43:05 +00003927 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
3928 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003929}
3930
3931
lrn@chromium.org303ada72010-10-27 09:33:13 +00003932static MaybeObject* Runtime_GetPropertyNames(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003933 HandleScope scope;
3934 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003935 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003936 return *GetKeysFor(object);
3937}
3938
3939
3940// Returns either a FixedArray as Runtime_GetPropertyNames,
3941// or, if the given object has an enum cache that contains
3942// all enumerable properties of the object and its prototypes
3943// have none, the map of the object. This is used to speed up
3944// the check for deletions during a for-in.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003945static MaybeObject* Runtime_GetPropertyNamesFast(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003946 ASSERT(args.length() == 1);
3947
3948 CONVERT_CHECKED(JSObject, raw_object, args[0]);
3949
3950 if (raw_object->IsSimpleEnum()) return raw_object->map();
3951
3952 HandleScope scope;
3953 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00003954 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
3955 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003956
3957 // Test again, since cache may have been built by preceding call.
3958 if (object->IsSimpleEnum()) return object->map();
3959
3960 return *content;
3961}
3962
3963
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003964// Find the length of the prototype chain that is to to handled as one. If a
3965// prototype object is hidden it is to be viewed as part of the the object it
3966// is prototype for.
3967static int LocalPrototypeChainLength(JSObject* obj) {
3968 int count = 1;
3969 Object* proto = obj->GetPrototype();
3970 while (proto->IsJSObject() &&
3971 JSObject::cast(proto)->map()->is_hidden_prototype()) {
3972 count++;
3973 proto = JSObject::cast(proto)->GetPrototype();
3974 }
3975 return count;
3976}
3977
3978
3979// Return the names of the local named properties.
3980// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00003981static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003982 HandleScope scope;
3983 ASSERT(args.length() == 1);
3984 if (!args[0]->IsJSObject()) {
3985 return Heap::undefined_value();
3986 }
3987 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3988
3989 // Skip the global proxy as it has no properties and always delegates to the
3990 // real global object.
3991 if (obj->IsJSGlobalProxy()) {
3992 // Only collect names if access is permitted.
3993 if (obj->IsAccessCheckNeeded() &&
3994 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
3995 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
3996 return *Factory::NewJSArray(0);
3997 }
3998 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
3999 }
4000
4001 // Find the number of objects making up this.
4002 int length = LocalPrototypeChainLength(*obj);
4003
4004 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004005 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004006 int total_property_count = 0;
4007 Handle<JSObject> jsproto = obj;
4008 for (int i = 0; i < length; i++) {
4009 // Only collect names if access is permitted.
4010 if (jsproto->IsAccessCheckNeeded() &&
4011 !Top::MayNamedAccess(*jsproto,
4012 Heap::undefined_value(),
4013 v8::ACCESS_KEYS)) {
4014 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4015 return *Factory::NewJSArray(0);
4016 }
4017 int n;
4018 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4019 local_property_count[i] = n;
4020 total_property_count += n;
4021 if (i < length - 1) {
4022 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4023 }
4024 }
4025
4026 // Allocate an array with storage for all the property names.
4027 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
4028
4029 // Get the property names.
4030 jsproto = obj;
4031 int proto_with_hidden_properties = 0;
4032 for (int i = 0; i < length; i++) {
4033 jsproto->GetLocalPropertyNames(*names,
4034 i == 0 ? 0 : local_property_count[i - 1]);
4035 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4036 proto_with_hidden_properties++;
4037 }
4038 if (i < length - 1) {
4039 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4040 }
4041 }
4042
4043 // Filter out name of hidden propeties object.
4044 if (proto_with_hidden_properties > 0) {
4045 Handle<FixedArray> old_names = names;
4046 names = Factory::NewFixedArray(
4047 names->length() - proto_with_hidden_properties);
4048 int dest_pos = 0;
4049 for (int i = 0; i < total_property_count; i++) {
4050 Object* name = old_names->get(i);
4051 if (name == Heap::hidden_symbol()) {
4052 continue;
4053 }
4054 names->set(dest_pos++, name);
4055 }
4056 }
4057
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004058 return *Factory::NewJSArrayWithElements(names);
4059}
4060
4061
4062// Return the names of the local indexed properties.
4063// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004064static MaybeObject* Runtime_GetLocalElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004065 HandleScope scope;
4066 ASSERT(args.length() == 1);
4067 if (!args[0]->IsJSObject()) {
4068 return Heap::undefined_value();
4069 }
4070 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4071
4072 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4073 Handle<FixedArray> names = Factory::NewFixedArray(n);
4074 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4075 return *Factory::NewJSArrayWithElements(names);
4076}
4077
4078
4079// Return information on whether an object has a named or indexed interceptor.
4080// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004081static MaybeObject* Runtime_GetInterceptorInfo(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004082 HandleScope scope;
4083 ASSERT(args.length() == 1);
4084 if (!args[0]->IsJSObject()) {
4085 return Smi::FromInt(0);
4086 }
4087 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4088
4089 int result = 0;
4090 if (obj->HasNamedInterceptor()) result |= 2;
4091 if (obj->HasIndexedInterceptor()) result |= 1;
4092
4093 return Smi::FromInt(result);
4094}
4095
4096
4097// Return property names from named interceptor.
4098// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004099static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004100 HandleScope scope;
4101 ASSERT(args.length() == 1);
4102 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4103
4104 if (obj->HasNamedInterceptor()) {
4105 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4106 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4107 }
4108 return Heap::undefined_value();
4109}
4110
4111
4112// Return element names from indexed interceptor.
4113// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004114static MaybeObject* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004115 HandleScope scope;
4116 ASSERT(args.length() == 1);
4117 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4118
4119 if (obj->HasIndexedInterceptor()) {
4120 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4121 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4122 }
4123 return Heap::undefined_value();
4124}
4125
4126
lrn@chromium.org303ada72010-10-27 09:33:13 +00004127static MaybeObject* Runtime_LocalKeys(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004128 ASSERT_EQ(args.length(), 1);
4129 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4130 HandleScope scope;
4131 Handle<JSObject> object(raw_object);
4132 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4133 LOCAL_ONLY);
4134 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4135 // property array and since the result is mutable we have to create
4136 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004137 int length = contents->length();
4138 Handle<FixedArray> copy = Factory::NewFixedArray(length);
4139 for (int i = 0; i < length; i++) {
4140 Object* entry = contents->get(i);
4141 if (entry->IsString()) {
4142 copy->set(i, entry);
4143 } else {
4144 ASSERT(entry->IsNumber());
4145 HandleScope scope;
4146 Handle<Object> entry_handle(entry);
4147 Handle<Object> entry_str = Factory::NumberToString(entry_handle);
4148 copy->set(i, *entry_str);
4149 }
4150 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004151 return *Factory::NewJSArrayWithElements(copy);
4152}
4153
4154
lrn@chromium.org303ada72010-10-27 09:33:13 +00004155static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004156 NoHandleAllocation ha;
4157 ASSERT(args.length() == 1);
4158
4159 // Compute the frame holding the arguments.
4160 JavaScriptFrameIterator it;
4161 it.AdvanceToArgumentsFrame();
4162 JavaScriptFrame* frame = it.frame();
4163
4164 // Get the actual number of provided arguments.
4165 const uint32_t n = frame->GetProvidedParametersCount();
4166
4167 // Try to convert the key to an index. If successful and within
4168 // index return the the argument from the frame.
4169 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004170 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004171 return frame->GetParameter(index);
4172 }
4173
4174 // Convert the key to a string.
4175 HandleScope scope;
4176 bool exception = false;
4177 Handle<Object> converted =
4178 Execution::ToString(args.at<Object>(0), &exception);
4179 if (exception) return Failure::Exception();
4180 Handle<String> key = Handle<String>::cast(converted);
4181
4182 // Try to convert the string key into an array index.
4183 if (key->AsArrayIndex(&index)) {
4184 if (index < n) {
4185 return frame->GetParameter(index);
4186 } else {
4187 return Top::initial_object_prototype()->GetElement(index);
4188 }
4189 }
4190
4191 // Handle special arguments properties.
4192 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
4193 if (key->Equals(Heap::callee_symbol())) return frame->function();
4194
4195 // Lookup in the initial Object.prototype object.
4196 return Top::initial_object_prototype()->GetProperty(*key);
4197}
4198
4199
lrn@chromium.org303ada72010-10-27 09:33:13 +00004200static MaybeObject* Runtime_ToFastProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004201 HandleScope scope;
4202
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004203 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004204 Handle<Object> object = args.at<Object>(0);
4205 if (object->IsJSObject()) {
4206 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004207 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004208 MaybeObject* ok = js_object->TransformToFastProperties(0);
4209 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004210 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004211 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004212 return *object;
4213}
4214
4215
lrn@chromium.org303ada72010-10-27 09:33:13 +00004216static MaybeObject* Runtime_ToSlowProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004217 HandleScope scope;
4218
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004219 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004220 Handle<Object> object = args.at<Object>(0);
4221 if (object->IsJSObject()) {
4222 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004223 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004224 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004225 return *object;
4226}
4227
4228
lrn@chromium.org303ada72010-10-27 09:33:13 +00004229static MaybeObject* Runtime_ToBool(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004230 NoHandleAllocation ha;
4231 ASSERT(args.length() == 1);
4232
4233 return args[0]->ToBoolean();
4234}
4235
4236
4237// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4238// Possible optimizations: put the type string into the oddballs.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004239static MaybeObject* Runtime_Typeof(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004240 NoHandleAllocation ha;
4241
4242 Object* obj = args[0];
4243 if (obj->IsNumber()) return Heap::number_symbol();
4244 HeapObject* heap_obj = HeapObject::cast(obj);
4245
4246 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004247 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004248
4249 InstanceType instance_type = heap_obj->map()->instance_type();
4250 if (instance_type < FIRST_NONSTRING_TYPE) {
4251 return Heap::string_symbol();
4252 }
4253
4254 switch (instance_type) {
4255 case ODDBALL_TYPE:
4256 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
4257 return Heap::boolean_symbol();
4258 }
4259 if (heap_obj->IsNull()) {
4260 return Heap::object_symbol();
4261 }
4262 ASSERT(heap_obj->IsUndefined());
4263 return Heap::undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004264 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004265 return Heap::function_symbol();
4266 default:
4267 // For any kind of object not handled above, the spec rule for
4268 // host objects gives that it is okay to return "object"
4269 return Heap::object_symbol();
4270 }
4271}
4272
4273
lrn@chromium.org25156de2010-04-06 13:10:27 +00004274static bool AreDigits(const char*s, int from, int to) {
4275 for (int i = from; i < to; i++) {
4276 if (s[i] < '0' || s[i] > '9') return false;
4277 }
4278
4279 return true;
4280}
4281
4282
4283static int ParseDecimalInteger(const char*s, int from, int to) {
4284 ASSERT(to - from < 10); // Overflow is not possible.
4285 ASSERT(from < to);
4286 int d = s[from] - '0';
4287
4288 for (int i = from + 1; i < to; i++) {
4289 d = 10 * d + (s[i] - '0');
4290 }
4291
4292 return d;
4293}
4294
4295
lrn@chromium.org303ada72010-10-27 09:33:13 +00004296static MaybeObject* Runtime_StringToNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004297 NoHandleAllocation ha;
4298 ASSERT(args.length() == 1);
4299 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004300 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004301
4302 // Fast case: short integer or some sorts of junk values.
4303 int len = subject->length();
4304 if (subject->IsSeqAsciiString()) {
4305 if (len == 0) return Smi::FromInt(0);
4306
4307 char const* data = SeqAsciiString::cast(subject)->GetChars();
4308 bool minus = (data[0] == '-');
4309 int start_pos = (minus ? 1 : 0);
4310
4311 if (start_pos == len) {
4312 return Heap::nan_value();
4313 } else if (data[start_pos] > '9') {
4314 // Fast check for a junk value. A valid string may start from a
4315 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4316 // the 'I' character ('Infinity'). All of that have codes not greater than
4317 // '9' except 'I'.
4318 if (data[start_pos] != 'I') {
4319 return Heap::nan_value();
4320 }
4321 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4322 // The maximal/minimal smi has 10 digits. If the string has less digits we
4323 // know it will fit into the smi-data type.
4324 int d = ParseDecimalInteger(data, start_pos, len);
4325 if (minus) {
4326 if (d == 0) return Heap::minus_zero_value();
4327 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004328 } else if (!subject->HasHashCode() &&
4329 len <= String::kMaxArrayIndexSize &&
4330 (len == 1 || data[0] != '0')) {
4331 // String hash is not calculated yet but all the data are present.
4332 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004333 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004334#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004335 subject->Hash(); // Force hash calculation.
4336 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4337 static_cast<int>(hash));
4338#endif
4339 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004340 }
4341 return Smi::FromInt(d);
4342 }
4343 }
4344
4345 // Slower case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004346 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
4347}
4348
4349
lrn@chromium.org303ada72010-10-27 09:33:13 +00004350static MaybeObject* Runtime_StringFromCharCodeArray(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004351 NoHandleAllocation ha;
4352 ASSERT(args.length() == 1);
4353
4354 CONVERT_CHECKED(JSArray, codes, args[0]);
4355 int length = Smi::cast(codes->length())->value();
4356
4357 // Check if the string can be ASCII.
4358 int i;
4359 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004360 Object* element;
4361 { MaybeObject* maybe_element = codes->GetElement(i);
4362 // We probably can't get an exception here, but just in order to enforce
4363 // the checking of inputs in the runtime calls we check here.
4364 if (!maybe_element->ToObject(&element)) return maybe_element;
4365 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004366 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4367 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4368 break;
4369 }
4370
lrn@chromium.org303ada72010-10-27 09:33:13 +00004371 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004372 if (i == length) { // The string is ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004373 maybe_object = Heap::AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004374 } else { // The string is not ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004375 maybe_object = Heap::AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004376 }
4377
lrn@chromium.org303ada72010-10-27 09:33:13 +00004378 Object* object = NULL;
4379 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004380 String* result = String::cast(object);
4381 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004382 Object* element;
4383 { MaybeObject* maybe_element = codes->GetElement(i);
4384 if (!maybe_element->ToObject(&element)) return maybe_element;
4385 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004386 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004387 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004388 }
4389 return result;
4390}
4391
4392
4393// kNotEscaped is generated by the following:
4394//
4395// #!/bin/perl
4396// for (my $i = 0; $i < 256; $i++) {
4397// print "\n" if $i % 16 == 0;
4398// my $c = chr($i);
4399// my $escaped = 1;
4400// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4401// print $escaped ? "0, " : "1, ";
4402// }
4403
4404
4405static bool IsNotEscaped(uint16_t character) {
4406 // Only for 8 bit characters, the rest are always escaped (in a different way)
4407 ASSERT(character < 256);
4408 static const char kNotEscaped[256] = {
4409 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4410 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4411 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4412 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4413 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4414 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4415 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4416 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4417 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4418 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4419 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4420 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4421 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4422 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4423 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4424 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4425 };
4426 return kNotEscaped[character] != 0;
4427}
4428
4429
lrn@chromium.org303ada72010-10-27 09:33:13 +00004430static MaybeObject* Runtime_URIEscape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004431 const char hex_chars[] = "0123456789ABCDEF";
4432 NoHandleAllocation ha;
4433 ASSERT(args.length() == 1);
4434 CONVERT_CHECKED(String, source, args[0]);
4435
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004436 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004437
4438 int escaped_length = 0;
4439 int length = source->length();
4440 {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004441 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004442 buffer->Reset(source);
4443 while (buffer->has_more()) {
4444 uint16_t character = buffer->GetNext();
4445 if (character >= 256) {
4446 escaped_length += 6;
4447 } else if (IsNotEscaped(character)) {
4448 escaped_length++;
4449 } else {
4450 escaped_length += 3;
4451 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004452 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004453 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004454 if (escaped_length > String::kMaxLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004455 Top::context()->mark_out_of_memory();
4456 return Failure::OutOfMemoryException();
4457 }
4458 }
4459 }
4460 // No length change implies no change. Return original string if no change.
4461 if (escaped_length == length) {
4462 return source;
4463 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004464 Object* o;
4465 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(escaped_length);
4466 if (!maybe_o->ToObject(&o)) return maybe_o;
4467 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004468 String* destination = String::cast(o);
4469 int dest_position = 0;
4470
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004471 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004472 buffer->Rewind();
4473 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004474 uint16_t chr = buffer->GetNext();
4475 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004476 destination->Set(dest_position, '%');
4477 destination->Set(dest_position+1, 'u');
4478 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4479 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4480 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4481 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004482 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004483 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004484 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004485 dest_position++;
4486 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004487 destination->Set(dest_position, '%');
4488 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4489 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004490 dest_position += 3;
4491 }
4492 }
4493 return destination;
4494}
4495
4496
4497static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4498 static const signed char kHexValue['g'] = {
4499 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4500 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4501 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4502 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4503 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4504 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4505 -1, 10, 11, 12, 13, 14, 15 };
4506
4507 if (character1 > 'f') return -1;
4508 int hi = kHexValue[character1];
4509 if (hi == -1) return -1;
4510 if (character2 > 'f') return -1;
4511 int lo = kHexValue[character2];
4512 if (lo == -1) return -1;
4513 return (hi << 4) + lo;
4514}
4515
4516
ager@chromium.org870a0b62008-11-04 11:43:05 +00004517static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004518 int i,
4519 int length,
4520 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004521 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004522 int32_t hi = 0;
4523 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004524 if (character == '%' &&
4525 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004526 source->Get(i + 1) == 'u' &&
4527 (hi = TwoDigitHex(source->Get(i + 2),
4528 source->Get(i + 3))) != -1 &&
4529 (lo = TwoDigitHex(source->Get(i + 4),
4530 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004531 *step = 6;
4532 return (hi << 8) + lo;
4533 } else if (character == '%' &&
4534 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004535 (lo = TwoDigitHex(source->Get(i + 1),
4536 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004537 *step = 3;
4538 return lo;
4539 } else {
4540 *step = 1;
4541 return character;
4542 }
4543}
4544
4545
lrn@chromium.org303ada72010-10-27 09:33:13 +00004546static MaybeObject* Runtime_URIUnescape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004547 NoHandleAllocation ha;
4548 ASSERT(args.length() == 1);
4549 CONVERT_CHECKED(String, source, args[0]);
4550
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004551 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004552
4553 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004554 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004555
4556 int unescaped_length = 0;
4557 for (int i = 0; i < length; unescaped_length++) {
4558 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004559 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004560 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004561 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004562 i += step;
4563 }
4564
4565 // No length change implies no change. Return original string if no change.
4566 if (unescaped_length == length)
4567 return source;
4568
lrn@chromium.org303ada72010-10-27 09:33:13 +00004569 Object* o;
4570 { MaybeObject* maybe_o = ascii ?
4571 Heap::AllocateRawAsciiString(unescaped_length) :
4572 Heap::AllocateRawTwoByteString(unescaped_length);
4573 if (!maybe_o->ToObject(&o)) return maybe_o;
4574 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004575 String* destination = String::cast(o);
4576
4577 int dest_position = 0;
4578 for (int i = 0; i < length; dest_position++) {
4579 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004580 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004581 i += step;
4582 }
4583 return destination;
4584}
4585
4586
lrn@chromium.org303ada72010-10-27 09:33:13 +00004587static MaybeObject* Runtime_StringParseInt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004588 NoHandleAllocation ha;
4589
4590 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004591 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004592
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004593 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004594
lrn@chromium.org25156de2010-04-06 13:10:27 +00004595 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
4596 double value = StringToInt(s, radix);
4597 return Heap::NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004598}
4599
4600
lrn@chromium.org303ada72010-10-27 09:33:13 +00004601static MaybeObject* Runtime_StringParseFloat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004602 NoHandleAllocation ha;
4603 CONVERT_CHECKED(String, str, args[0]);
4604
4605 // ECMA-262 section 15.1.2.3, empty string is NaN
4606 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
4607
4608 // Create a number object from the value.
4609 return Heap::NumberFromDouble(value);
4610}
4611
4612
4613static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
4614static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
4615
4616
4617template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00004618MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
4619 String* s,
4620 int length,
4621 int input_string_length,
4622 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004623 // We try this twice, once with the assumption that the result is no longer
4624 // than the input and, if that assumption breaks, again with the exact
4625 // length. This may not be pretty, but it is nicer than what was here before
4626 // and I hereby claim my vaffel-is.
4627 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004628 // Allocate the resulting string.
4629 //
4630 // NOTE: This assumes that the upper/lower case of an ascii
4631 // character is also ascii. This is currently the case, but it
4632 // might break in the future if we implement more context and locale
4633 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004634 Object* o;
4635 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
4636 ? Heap::AllocateRawAsciiString(length)
4637 : Heap::AllocateRawTwoByteString(length);
4638 if (!maybe_o->ToObject(&o)) return maybe_o;
4639 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004640 String* result = String::cast(o);
4641 bool has_changed_character = false;
4642
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004643 // Convert all characters to upper case, assuming that they will fit
4644 // in the buffer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004645 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004646 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004647 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004648 // We can assume that the string is not empty
4649 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004650 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004651 bool has_next = buffer->has_more();
4652 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004653 int char_length = mapping->get(current, next, chars);
4654 if (char_length == 0) {
4655 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004656 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004657 i++;
4658 } else if (char_length == 1) {
4659 // Common case: converting the letter resulted in one character.
4660 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004661 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004662 has_changed_character = true;
4663 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004664 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004665 // We've assumed that the result would be as long as the
4666 // input but here is a character that converts to several
4667 // characters. No matter, we calculate the exact length
4668 // of the result and try the whole thing again.
4669 //
4670 // Note that this leaves room for optimization. We could just
4671 // memcpy what we already have to the result string. Also,
4672 // the result string is the last object allocated we could
4673 // "realloc" it and probably, in the vast majority of cases,
4674 // extend the existing string to be able to hold the full
4675 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004676 int next_length = 0;
4677 if (has_next) {
4678 next_length = mapping->get(next, 0, chars);
4679 if (next_length == 0) next_length = 1;
4680 }
4681 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004682 while (buffer->has_more()) {
4683 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004684 // NOTE: we use 0 as the next character here because, while
4685 // the next character may affect what a character converts to,
4686 // it does not in any case affect the length of what it convert
4687 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004688 int char_length = mapping->get(current, 0, chars);
4689 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00004690 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004691 if (current_length > Smi::kMaxValue) {
4692 Top::context()->mark_out_of_memory();
4693 return Failure::OutOfMemoryException();
4694 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004695 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004696 // Try again with the real length.
4697 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004698 } else {
4699 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004700 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004701 i++;
4702 }
4703 has_changed_character = true;
4704 }
4705 current = next;
4706 }
4707 if (has_changed_character) {
4708 return result;
4709 } else {
4710 // If we didn't actually change anything in doing the conversion
4711 // we simple return the result and let the converted string
4712 // become garbage; there is no reason to keep two identical strings
4713 // alive.
4714 return s;
4715 }
4716}
4717
4718
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004719namespace {
4720
lrn@chromium.org303ada72010-10-27 09:33:13 +00004721static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
4722
4723
4724// Given a word and two range boundaries returns a word with high bit
4725// set in every byte iff the corresponding input byte was strictly in
4726// the range (m, n). All the other bits in the result are cleared.
4727// This function is only useful when it can be inlined and the
4728// boundaries are statically known.
4729// Requires: all bytes in the input word and the boundaries must be
4730// ascii (less than 0x7F).
4731static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
4732 // Every byte in an ascii string is less than or equal to 0x7F.
4733 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
4734 // Use strict inequalities since in edge cases the function could be
4735 // further simplified.
4736 ASSERT(0 < m && m < n && n < 0x7F);
4737 // Has high bit set in every w byte less than n.
4738 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
4739 // Has high bit set in every w byte greater than m.
4740 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
4741 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
4742}
4743
4744
4745enum AsciiCaseConversion {
4746 ASCII_TO_LOWER,
4747 ASCII_TO_UPPER
4748};
4749
4750
4751template <AsciiCaseConversion dir>
4752struct FastAsciiConverter {
4753 static bool Convert(char* dst, char* src, int length) {
4754#ifdef DEBUG
4755 char* saved_dst = dst;
4756 char* saved_src = src;
4757#endif
4758 // We rely on the distance between upper and lower case letters
4759 // being a known power of 2.
4760 ASSERT('a' - 'A' == (1 << 5));
4761 // Boundaries for the range of input characters than require conversion.
4762 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
4763 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
4764 bool changed = false;
4765 char* const limit = src + length;
4766#ifdef V8_HOST_CAN_READ_UNALIGNED
4767 // Process the prefix of the input that requires no conversion one
4768 // (machine) word at a time.
4769 while (src <= limit - sizeof(uintptr_t)) {
4770 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
4771 if (AsciiRangeMask(w, lo, hi) != 0) {
4772 changed = true;
4773 break;
4774 }
4775 *reinterpret_cast<uintptr_t*>(dst) = w;
4776 src += sizeof(uintptr_t);
4777 dst += sizeof(uintptr_t);
4778 }
4779 // Process the remainder of the input performing conversion when
4780 // required one word at a time.
4781 while (src <= limit - sizeof(uintptr_t)) {
4782 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
4783 uintptr_t m = AsciiRangeMask(w, lo, hi);
4784 // The mask has high (7th) bit set in every byte that needs
4785 // conversion and we know that the distance between cases is
4786 // 1 << 5.
4787 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
4788 src += sizeof(uintptr_t);
4789 dst += sizeof(uintptr_t);
4790 }
4791#endif
4792 // Process the last few bytes of the input (or the whole input if
4793 // unaligned access is not supported).
4794 while (src < limit) {
4795 char c = *src;
4796 if (lo < c && c < hi) {
4797 c ^= (1 << 5);
4798 changed = true;
4799 }
4800 *dst = c;
4801 ++src;
4802 ++dst;
4803 }
4804#ifdef DEBUG
4805 CheckConvert(saved_dst, saved_src, length, changed);
4806#endif
4807 return changed;
4808 }
4809
4810#ifdef DEBUG
4811 static void CheckConvert(char* dst, char* src, int length, bool changed) {
4812 bool expected_changed = false;
4813 for (int i = 0; i < length; i++) {
4814 if (dst[i] == src[i]) continue;
4815 expected_changed = true;
4816 if (dir == ASCII_TO_LOWER) {
4817 ASSERT('A' <= src[i] && src[i] <= 'Z');
4818 ASSERT(dst[i] == src[i] + ('a' - 'A'));
4819 } else {
4820 ASSERT(dir == ASCII_TO_UPPER);
4821 ASSERT('a' <= src[i] && src[i] <= 'z');
4822 ASSERT(dst[i] == src[i] - ('a' - 'A'));
4823 }
4824 }
4825 ASSERT(expected_changed == changed);
4826 }
4827#endif
4828};
4829
4830
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004831struct ToLowerTraits {
4832 typedef unibrow::ToLowercase UnibrowConverter;
4833
lrn@chromium.org303ada72010-10-27 09:33:13 +00004834 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004835};
4836
4837
4838struct ToUpperTraits {
4839 typedef unibrow::ToUppercase UnibrowConverter;
4840
lrn@chromium.org303ada72010-10-27 09:33:13 +00004841 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004842};
4843
4844} // namespace
4845
4846
4847template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00004848MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004849 Arguments args,
4850 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004851 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004852 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00004853 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004854
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004855 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004856 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004857 if (length == 0) return s;
4858
4859 // Simpler handling of ascii strings.
4860 //
4861 // NOTE: This assumes that the upper/lower case of an ascii
4862 // character is also ascii. This is currently the case, but it
4863 // might break in the future if we implement more context and locale
4864 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00004865 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004866 Object* o;
4867 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(length);
4868 if (!maybe_o->ToObject(&o)) return maybe_o;
4869 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004870 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004871 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00004872 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004873 return has_changed_character ? result : s;
4874 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004875
lrn@chromium.org303ada72010-10-27 09:33:13 +00004876 Object* answer;
4877 { MaybeObject* maybe_answer = ConvertCaseHelper(s, length, length, mapping);
4878 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
4879 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004880 if (answer->IsSmi()) {
4881 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004882 { MaybeObject* maybe_answer =
4883 ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
4884 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
4885 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004886 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004887 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004888}
4889
4890
lrn@chromium.org303ada72010-10-27 09:33:13 +00004891static MaybeObject* Runtime_StringToLowerCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004892 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004893}
4894
4895
lrn@chromium.org303ada72010-10-27 09:33:13 +00004896static MaybeObject* Runtime_StringToUpperCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004897 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004898}
4899
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004900
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004901static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
4902 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
4903}
4904
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004905
lrn@chromium.org303ada72010-10-27 09:33:13 +00004906static MaybeObject* Runtime_StringTrim(Arguments args) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004907 NoHandleAllocation ha;
4908 ASSERT(args.length() == 3);
4909
4910 CONVERT_CHECKED(String, s, args[0]);
4911 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
4912 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
4913
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004914 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004915 int length = s->length();
4916
4917 int left = 0;
4918 if (trimLeft) {
4919 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
4920 left++;
4921 }
4922 }
4923
4924 int right = length;
4925 if (trimRight) {
4926 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
4927 right--;
4928 }
4929 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004930 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004931}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004932
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004933
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004934template <typename SubjectChar, typename PatternChar>
4935void FindStringIndices(Vector<const SubjectChar> subject,
4936 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004937 ZoneList<int>* indices,
4938 unsigned int limit) {
4939 ASSERT(limit > 0);
4940 // Collect indices of pattern in subject, and the end-of-string index.
4941 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00004942 StringSearch<PatternChar, SubjectChar> search(pattern);
4943 int pattern_length = pattern.length();
4944 int index = 0;
4945 while (limit > 0) {
4946 index = search.Search(subject, index);
4947 if (index < 0) return;
4948 indices->Add(index);
4949 index += pattern_length;
4950 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004951 }
4952}
4953
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004954
lrn@chromium.org303ada72010-10-27 09:33:13 +00004955static MaybeObject* Runtime_StringSplit(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004956 ASSERT(args.length() == 3);
4957 HandleScope handle_scope;
4958 CONVERT_ARG_CHECKED(String, subject, 0);
4959 CONVERT_ARG_CHECKED(String, pattern, 1);
4960 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
4961
4962 int subject_length = subject->length();
4963 int pattern_length = pattern->length();
4964 RUNTIME_ASSERT(pattern_length > 0);
4965
4966 // The limit can be very large (0xffffffffu), but since the pattern
4967 // isn't empty, we can never create more parts than ~half the length
4968 // of the subject.
4969
4970 if (!subject->IsFlat()) FlattenString(subject);
4971
4972 static const int kMaxInitialListCapacity = 16;
4973
4974 ZoneScope scope(DELETE_ON_EXIT);
4975
4976 // Find (up to limit) indices of separator and end-of-string in subject
4977 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
4978 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004979 if (!pattern->IsFlat()) FlattenString(pattern);
4980
4981 // No allocation block.
4982 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00004983 AssertNoAllocation nogc;
4984 if (subject->IsAsciiRepresentation()) {
4985 Vector<const char> subject_vector = subject->ToAsciiVector();
4986 if (pattern->IsAsciiRepresentation()) {
4987 FindStringIndices(subject_vector,
4988 pattern->ToAsciiVector(),
4989 &indices,
4990 limit);
4991 } else {
4992 FindStringIndices(subject_vector,
4993 pattern->ToUC16Vector(),
4994 &indices,
4995 limit);
4996 }
4997 } else {
4998 Vector<const uc16> subject_vector = subject->ToUC16Vector();
4999 if (pattern->IsAsciiRepresentation()) {
5000 FindStringIndices(subject_vector,
5001 pattern->ToAsciiVector(),
5002 &indices,
5003 limit);
5004 } else {
5005 FindStringIndices(subject_vector,
5006 pattern->ToUC16Vector(),
5007 &indices,
5008 limit);
5009 }
5010 }
5011 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005012
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005013 if (static_cast<uint32_t>(indices.length()) < limit) {
5014 indices.Add(subject_length);
5015 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005016
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005017 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005018
5019 // Create JSArray of substrings separated by separator.
5020 int part_count = indices.length();
5021
5022 Handle<JSArray> result = Factory::NewJSArray(part_count);
5023 result->set_length(Smi::FromInt(part_count));
5024
5025 ASSERT(result->HasFastElements());
5026
5027 if (part_count == 1 && indices.at(0) == subject_length) {
5028 FixedArray::cast(result->elements())->set(0, *subject);
5029 return *result;
5030 }
5031
5032 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5033 int part_start = 0;
5034 for (int i = 0; i < part_count; i++) {
5035 HandleScope local_loop_handle;
5036 int part_end = indices.at(i);
5037 Handle<String> substring =
5038 Factory::NewSubString(subject, part_start, part_end);
5039 elements->set(i, *substring);
5040 part_start = part_end + pattern_length;
5041 }
5042
5043 return *result;
5044}
5045
5046
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005047// Copies ascii characters to the given fixed array looking up
5048// one-char strings in the cache. Gives up on the first char that is
5049// not in the cache and fills the remainder with smi zeros. Returns
5050// the length of the successfully copied prefix.
5051static int CopyCachedAsciiCharsToArray(const char* chars,
5052 FixedArray* elements,
5053 int length) {
5054 AssertNoAllocation nogc;
5055 FixedArray* ascii_cache = Heap::single_character_string_cache();
5056 Object* undefined = Heap::undefined_value();
5057 int i;
5058 for (i = 0; i < length; ++i) {
5059 Object* value = ascii_cache->get(chars[i]);
5060 if (value == undefined) break;
5061 ASSERT(!Heap::InNewSpace(value));
5062 elements->set(i, value, SKIP_WRITE_BARRIER);
5063 }
5064 if (i < length) {
5065 ASSERT(Smi::FromInt(0) == 0);
5066 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5067 }
5068#ifdef DEBUG
5069 for (int j = 0; j < length; ++j) {
5070 Object* element = elements->get(j);
5071 ASSERT(element == Smi::FromInt(0) ||
5072 (element->IsString() && String::cast(element)->LooksValid()));
5073 }
5074#endif
5075 return i;
5076}
5077
5078
5079// Converts a String to JSArray.
5080// For example, "foo" => ["f", "o", "o"].
lrn@chromium.org303ada72010-10-27 09:33:13 +00005081static MaybeObject* Runtime_StringToArray(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005082 HandleScope scope;
5083 ASSERT(args.length() == 1);
5084 CONVERT_ARG_CHECKED(String, s, 0);
5085
5086 s->TryFlatten();
5087 const int length = s->length();
5088
5089 Handle<FixedArray> elements;
5090 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005091 Object* obj;
5092 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(length);
5093 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5094 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005095 elements = Handle<FixedArray>(FixedArray::cast(obj));
5096
5097 Vector<const char> chars = s->ToAsciiVector();
5098 // Note, this will initialize all elements (not only the prefix)
5099 // to prevent GC from seeing partially initialized array.
5100 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
5101 *elements,
5102 length);
5103
5104 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005105 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5106 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005107 }
5108 } else {
5109 elements = Factory::NewFixedArray(length);
5110 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005111 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5112 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005113 }
5114 }
5115
5116#ifdef DEBUG
5117 for (int i = 0; i < length; ++i) {
5118 ASSERT(String::cast(elements->get(i))->length() == 1);
5119 }
5120#endif
5121
5122 return *Factory::NewJSArrayWithElements(elements);
5123}
5124
5125
lrn@chromium.org303ada72010-10-27 09:33:13 +00005126static MaybeObject* Runtime_NewStringWrapper(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005127 NoHandleAllocation ha;
5128 ASSERT(args.length() == 1);
5129 CONVERT_CHECKED(String, value, args[0]);
5130 return value->ToObject();
5131}
5132
5133
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005134bool Runtime::IsUpperCaseChar(uint16_t ch) {
5135 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
5136 int char_length = to_upper_mapping.get(ch, 0, chars);
5137 return char_length == 0;
5138}
5139
5140
lrn@chromium.org303ada72010-10-27 09:33:13 +00005141static MaybeObject* Runtime_NumberToString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005142 NoHandleAllocation ha;
5143 ASSERT(args.length() == 1);
5144
5145 Object* number = args[0];
5146 RUNTIME_ASSERT(number->IsNumber());
5147
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005148 return Heap::NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005149}
5150
5151
lrn@chromium.org303ada72010-10-27 09:33:13 +00005152static MaybeObject* Runtime_NumberToStringSkipCache(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005153 NoHandleAllocation ha;
5154 ASSERT(args.length() == 1);
5155
5156 Object* number = args[0];
5157 RUNTIME_ASSERT(number->IsNumber());
5158
5159 return Heap::NumberToString(number, false);
5160}
5161
5162
lrn@chromium.org303ada72010-10-27 09:33:13 +00005163static MaybeObject* Runtime_NumberToInteger(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005164 NoHandleAllocation ha;
5165 ASSERT(args.length() == 1);
5166
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005167 CONVERT_DOUBLE_CHECKED(number, args[0]);
5168
5169 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5170 if (number > 0 && number <= Smi::kMaxValue) {
5171 return Smi::FromInt(static_cast<int>(number));
5172 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005173 return Heap::NumberFromDouble(DoubleToInteger(number));
5174}
5175
5176
lrn@chromium.org303ada72010-10-27 09:33:13 +00005177static MaybeObject* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005178 NoHandleAllocation ha;
5179 ASSERT(args.length() == 1);
5180
5181 CONVERT_DOUBLE_CHECKED(number, args[0]);
5182
5183 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5184 if (number > 0 && number <= Smi::kMaxValue) {
5185 return Smi::FromInt(static_cast<int>(number));
5186 }
5187
5188 double double_value = DoubleToInteger(number);
5189 // Map both -0 and +0 to +0.
5190 if (double_value == 0) double_value = 0;
5191
5192 return Heap::NumberFromDouble(double_value);
5193}
5194
5195
lrn@chromium.org303ada72010-10-27 09:33:13 +00005196static MaybeObject* Runtime_NumberToJSUint32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005197 NoHandleAllocation ha;
5198 ASSERT(args.length() == 1);
5199
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005200 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005201 return Heap::NumberFromUint32(number);
5202}
5203
5204
lrn@chromium.org303ada72010-10-27 09:33:13 +00005205static MaybeObject* Runtime_NumberToJSInt32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005206 NoHandleAllocation ha;
5207 ASSERT(args.length() == 1);
5208
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005209 CONVERT_DOUBLE_CHECKED(number, args[0]);
5210
5211 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5212 if (number > 0 && number <= Smi::kMaxValue) {
5213 return Smi::FromInt(static_cast<int>(number));
5214 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005215 return Heap::NumberFromInt32(DoubleToInt32(number));
5216}
5217
5218
ager@chromium.org870a0b62008-11-04 11:43:05 +00005219// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5220// a small integer.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005221static MaybeObject* Runtime_NumberToSmi(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005222 NoHandleAllocation ha;
5223 ASSERT(args.length() == 1);
5224
5225 Object* obj = args[0];
5226 if (obj->IsSmi()) {
5227 return obj;
5228 }
5229 if (obj->IsHeapNumber()) {
5230 double value = HeapNumber::cast(obj)->value();
5231 int int_value = FastD2I(value);
5232 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5233 return Smi::FromInt(int_value);
5234 }
5235 }
5236 return Heap::nan_value();
5237}
5238
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005239
lrn@chromium.org303ada72010-10-27 09:33:13 +00005240static MaybeObject* Runtime_NumberAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005241 NoHandleAllocation ha;
5242 ASSERT(args.length() == 2);
5243
5244 CONVERT_DOUBLE_CHECKED(x, args[0]);
5245 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005246 return Heap::NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005247}
5248
5249
lrn@chromium.org303ada72010-10-27 09:33:13 +00005250static MaybeObject* Runtime_NumberSub(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005251 NoHandleAllocation ha;
5252 ASSERT(args.length() == 2);
5253
5254 CONVERT_DOUBLE_CHECKED(x, args[0]);
5255 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005256 return Heap::NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005257}
5258
5259
lrn@chromium.org303ada72010-10-27 09:33:13 +00005260static MaybeObject* Runtime_NumberMul(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005261 NoHandleAllocation ha;
5262 ASSERT(args.length() == 2);
5263
5264 CONVERT_DOUBLE_CHECKED(x, args[0]);
5265 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005266 return Heap::NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005267}
5268
5269
lrn@chromium.org303ada72010-10-27 09:33:13 +00005270static MaybeObject* Runtime_NumberUnaryMinus(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005271 NoHandleAllocation ha;
5272 ASSERT(args.length() == 1);
5273
5274 CONVERT_DOUBLE_CHECKED(x, args[0]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005275 return Heap::NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005276}
5277
5278
lrn@chromium.org303ada72010-10-27 09:33:13 +00005279static MaybeObject* Runtime_NumberAlloc(Arguments args) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005280 NoHandleAllocation ha;
5281 ASSERT(args.length() == 0);
5282
5283 return Heap::NumberFromDouble(9876543210.0);
5284}
5285
5286
lrn@chromium.org303ada72010-10-27 09:33:13 +00005287static MaybeObject* Runtime_NumberDiv(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005288 NoHandleAllocation ha;
5289 ASSERT(args.length() == 2);
5290
5291 CONVERT_DOUBLE_CHECKED(x, args[0]);
5292 CONVERT_DOUBLE_CHECKED(y, args[1]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005293 return Heap::NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005294}
5295
5296
lrn@chromium.org303ada72010-10-27 09:33:13 +00005297static MaybeObject* Runtime_NumberMod(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005298 NoHandleAllocation ha;
5299 ASSERT(args.length() == 2);
5300
5301 CONVERT_DOUBLE_CHECKED(x, args[0]);
5302 CONVERT_DOUBLE_CHECKED(y, args[1]);
5303
ager@chromium.org3811b432009-10-28 14:53:37 +00005304 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005305 // NumberFromDouble may return a Smi instead of a Number object
5306 return Heap::NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005307}
5308
5309
lrn@chromium.org303ada72010-10-27 09:33:13 +00005310static MaybeObject* Runtime_StringAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005311 NoHandleAllocation ha;
5312 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005313 CONVERT_CHECKED(String, str1, args[0]);
5314 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005315 Counters::string_add_runtime.Increment();
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005316 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005317}
5318
5319
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005320template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005321static inline void StringBuilderConcatHelper(String* special,
5322 sinkchar* sink,
5323 FixedArray* fixed_array,
5324 int array_length) {
5325 int position = 0;
5326 for (int i = 0; i < array_length; i++) {
5327 Object* element = fixed_array->get(i);
5328 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005329 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005330 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005331 int pos;
5332 int len;
5333 if (encoded_slice > 0) {
5334 // Position and length encoded in one smi.
5335 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5336 len = StringBuilderSubstringLength::decode(encoded_slice);
5337 } else {
5338 // Position and length encoded in two smis.
5339 Object* obj = fixed_array->get(++i);
5340 ASSERT(obj->IsSmi());
5341 pos = Smi::cast(obj)->value();
5342 len = -encoded_slice;
5343 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005344 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005345 sink + position,
5346 pos,
5347 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005348 position += len;
5349 } else {
5350 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005351 int element_length = string->length();
5352 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005353 position += element_length;
5354 }
5355 }
5356}
5357
5358
lrn@chromium.org303ada72010-10-27 09:33:13 +00005359static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005360 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005361 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005362 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005363 if (!args[1]->IsSmi()) {
5364 Top::context()->mark_out_of_memory();
5365 return Failure::OutOfMemoryException();
5366 }
5367 int array_length = Smi::cast(args[1])->value();
5368 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005369
5370 // This assumption is used by the slice encoding in one or two smis.
5371 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5372
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005373 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005374 if (!array->HasFastElements()) {
5375 return Top::Throw(Heap::illegal_argument_symbol());
5376 }
5377 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005378 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005379 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005380 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005381
5382 if (array_length == 0) {
5383 return Heap::empty_string();
5384 } else if (array_length == 1) {
5385 Object* first = fixed_array->get(0);
5386 if (first->IsString()) return first;
5387 }
5388
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005389 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005390 int position = 0;
5391 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005392 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005393 Object* elt = fixed_array->get(i);
5394 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005395 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005396 int smi_value = Smi::cast(elt)->value();
5397 int pos;
5398 int len;
5399 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005400 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005401 pos = StringBuilderSubstringPosition::decode(smi_value);
5402 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005403 } else {
5404 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005405 len = -smi_value;
5406 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005407 i++;
5408 if (i >= array_length) {
5409 return Top::Throw(Heap::illegal_argument_symbol());
5410 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005411 Object* next_smi = fixed_array->get(i);
5412 if (!next_smi->IsSmi()) {
5413 return Top::Throw(Heap::illegal_argument_symbol());
5414 }
5415 pos = Smi::cast(next_smi)->value();
5416 if (pos < 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005417 return Top::Throw(Heap::illegal_argument_symbol());
5418 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005419 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005420 ASSERT(pos >= 0);
5421 ASSERT(len >= 0);
5422 if (pos > special_length || len > special_length - pos) {
5423 return Top::Throw(Heap::illegal_argument_symbol());
5424 }
5425 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005426 } else if (elt->IsString()) {
5427 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005428 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005429 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005430 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005431 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005432 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005433 } else {
5434 return Top::Throw(Heap::illegal_argument_symbol());
5435 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005436 if (increment > String::kMaxLength - position) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005437 Top::context()->mark_out_of_memory();
5438 return Failure::OutOfMemoryException();
5439 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005440 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005441 }
5442
5443 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005444 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005445
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005446 if (ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005447 { MaybeObject* maybe_object = Heap::AllocateRawAsciiString(length);
5448 if (!maybe_object->ToObject(&object)) return maybe_object;
5449 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005450 SeqAsciiString* answer = SeqAsciiString::cast(object);
5451 StringBuilderConcatHelper(special,
5452 answer->GetChars(),
5453 fixed_array,
5454 array_length);
5455 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005456 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005457 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5458 if (!maybe_object->ToObject(&object)) return maybe_object;
5459 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005460 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5461 StringBuilderConcatHelper(special,
5462 answer->GetChars(),
5463 fixed_array,
5464 array_length);
5465 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005466 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005467}
5468
5469
lrn@chromium.org303ada72010-10-27 09:33:13 +00005470static MaybeObject* Runtime_NumberOr(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(x | y);
5477}
5478
5479
lrn@chromium.org303ada72010-10-27 09:33:13 +00005480static MaybeObject* Runtime_NumberAnd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005481 NoHandleAllocation ha;
5482 ASSERT(args.length() == 2);
5483
5484 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5485 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5486 return Heap::NumberFromInt32(x & y);
5487}
5488
5489
lrn@chromium.org303ada72010-10-27 09:33:13 +00005490static MaybeObject* Runtime_NumberXor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005491 NoHandleAllocation ha;
5492 ASSERT(args.length() == 2);
5493
5494 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5495 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5496 return Heap::NumberFromInt32(x ^ y);
5497}
5498
5499
lrn@chromium.org303ada72010-10-27 09:33:13 +00005500static MaybeObject* Runtime_NumberNot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005501 NoHandleAllocation ha;
5502 ASSERT(args.length() == 1);
5503
5504 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5505 return Heap::NumberFromInt32(~x);
5506}
5507
5508
lrn@chromium.org303ada72010-10-27 09:33:13 +00005509static MaybeObject* Runtime_NumberShl(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005510 NoHandleAllocation ha;
5511 ASSERT(args.length() == 2);
5512
5513 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5514 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5515 return Heap::NumberFromInt32(x << (y & 0x1f));
5516}
5517
5518
lrn@chromium.org303ada72010-10-27 09:33:13 +00005519static MaybeObject* Runtime_NumberShr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005520 NoHandleAllocation ha;
5521 ASSERT(args.length() == 2);
5522
5523 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
5524 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5525 return Heap::NumberFromUint32(x >> (y & 0x1f));
5526}
5527
5528
lrn@chromium.org303ada72010-10-27 09:33:13 +00005529static MaybeObject* Runtime_NumberSar(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005530 NoHandleAllocation ha;
5531 ASSERT(args.length() == 2);
5532
5533 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5534 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5535 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
5536}
5537
5538
lrn@chromium.org303ada72010-10-27 09:33:13 +00005539static MaybeObject* Runtime_NumberEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005540 NoHandleAllocation ha;
5541 ASSERT(args.length() == 2);
5542
5543 CONVERT_DOUBLE_CHECKED(x, args[0]);
5544 CONVERT_DOUBLE_CHECKED(y, args[1]);
5545 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
5546 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
5547 if (x == y) return Smi::FromInt(EQUAL);
5548 Object* result;
5549 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
5550 result = Smi::FromInt(EQUAL);
5551 } else {
5552 result = Smi::FromInt(NOT_EQUAL);
5553 }
5554 return result;
5555}
5556
5557
lrn@chromium.org303ada72010-10-27 09:33:13 +00005558static MaybeObject* Runtime_StringEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005559 NoHandleAllocation ha;
5560 ASSERT(args.length() == 2);
5561
5562 CONVERT_CHECKED(String, x, args[0]);
5563 CONVERT_CHECKED(String, y, args[1]);
5564
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005565 bool not_equal = !x->Equals(y);
5566 // This is slightly convoluted because the value that signifies
5567 // equality is 0 and inequality is 1 so we have to negate the result
5568 // from String::Equals.
5569 ASSERT(not_equal == 0 || not_equal == 1);
5570 STATIC_CHECK(EQUAL == 0);
5571 STATIC_CHECK(NOT_EQUAL == 1);
5572 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005573}
5574
5575
lrn@chromium.org303ada72010-10-27 09:33:13 +00005576static MaybeObject* Runtime_NumberCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005577 NoHandleAllocation ha;
5578 ASSERT(args.length() == 3);
5579
5580 CONVERT_DOUBLE_CHECKED(x, args[0]);
5581 CONVERT_DOUBLE_CHECKED(y, args[1]);
5582 if (isnan(x) || isnan(y)) return args[2];
5583 if (x == y) return Smi::FromInt(EQUAL);
5584 if (isless(x, y)) return Smi::FromInt(LESS);
5585 return Smi::FromInt(GREATER);
5586}
5587
5588
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005589// Compare two Smis as if they were converted to strings and then
5590// compared lexicographically.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005591static MaybeObject* Runtime_SmiLexicographicCompare(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005592 NoHandleAllocation ha;
5593 ASSERT(args.length() == 2);
5594
5595 // Arrays for the individual characters of the two Smis. Smis are
5596 // 31 bit integers and 10 decimal digits are therefore enough.
5597 static int x_elms[10];
5598 static int y_elms[10];
5599
5600 // Extract the integer values from the Smis.
5601 CONVERT_CHECKED(Smi, x, args[0]);
5602 CONVERT_CHECKED(Smi, y, args[1]);
5603 int x_value = x->value();
5604 int y_value = y->value();
5605
5606 // If the integers are equal so are the string representations.
5607 if (x_value == y_value) return Smi::FromInt(EQUAL);
5608
5609 // If one of the integers are zero the normal integer order is the
5610 // same as the lexicographic order of the string representations.
5611 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
5612
ager@chromium.org32912102009-01-16 10:38:43 +00005613 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005614 // smallest because the char code of '-' is less than the char code
5615 // of any digit. Otherwise, we make both values positive.
5616 if (x_value < 0 || y_value < 0) {
5617 if (y_value >= 0) return Smi::FromInt(LESS);
5618 if (x_value >= 0) return Smi::FromInt(GREATER);
5619 x_value = -x_value;
5620 y_value = -y_value;
5621 }
5622
5623 // Convert the integers to arrays of their decimal digits.
5624 int x_index = 0;
5625 int y_index = 0;
5626 while (x_value > 0) {
5627 x_elms[x_index++] = x_value % 10;
5628 x_value /= 10;
5629 }
5630 while (y_value > 0) {
5631 y_elms[y_index++] = y_value % 10;
5632 y_value /= 10;
5633 }
5634
5635 // Loop through the arrays of decimal digits finding the first place
5636 // where they differ.
5637 while (--x_index >= 0 && --y_index >= 0) {
5638 int diff = x_elms[x_index] - y_elms[y_index];
5639 if (diff != 0) return Smi::FromInt(diff);
5640 }
5641
5642 // If one array is a suffix of the other array, the longest array is
5643 // the representation of the largest of the Smis in the
5644 // lexicographic ordering.
5645 return Smi::FromInt(x_index - y_index);
5646}
5647
5648
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005649static Object* StringInputBufferCompare(String* x, String* y) {
5650 static StringInputBuffer bufx;
5651 static StringInputBuffer bufy;
5652 bufx.Reset(x);
5653 bufy.Reset(y);
5654 while (bufx.has_more() && bufy.has_more()) {
5655 int d = bufx.GetNext() - bufy.GetNext();
5656 if (d < 0) return Smi::FromInt(LESS);
5657 else if (d > 0) return Smi::FromInt(GREATER);
5658 }
5659
5660 // x is (non-trivial) prefix of y:
5661 if (bufy.has_more()) return Smi::FromInt(LESS);
5662 // y is prefix of x:
5663 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
5664}
5665
5666
5667static Object* FlatStringCompare(String* x, String* y) {
5668 ASSERT(x->IsFlat());
5669 ASSERT(y->IsFlat());
5670 Object* equal_prefix_result = Smi::FromInt(EQUAL);
5671 int prefix_length = x->length();
5672 if (y->length() < prefix_length) {
5673 prefix_length = y->length();
5674 equal_prefix_result = Smi::FromInt(GREATER);
5675 } else if (y->length() > prefix_length) {
5676 equal_prefix_result = Smi::FromInt(LESS);
5677 }
5678 int r;
5679 if (x->IsAsciiRepresentation()) {
5680 Vector<const char> x_chars = x->ToAsciiVector();
5681 if (y->IsAsciiRepresentation()) {
5682 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005683 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005684 } else {
5685 Vector<const uc16> y_chars = y->ToUC16Vector();
5686 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5687 }
5688 } else {
5689 Vector<const uc16> x_chars = x->ToUC16Vector();
5690 if (y->IsAsciiRepresentation()) {
5691 Vector<const char> y_chars = y->ToAsciiVector();
5692 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5693 } else {
5694 Vector<const uc16> y_chars = y->ToUC16Vector();
5695 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5696 }
5697 }
5698 Object* result;
5699 if (r == 0) {
5700 result = equal_prefix_result;
5701 } else {
5702 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
5703 }
5704 ASSERT(result == StringInputBufferCompare(x, y));
5705 return result;
5706}
5707
5708
lrn@chromium.org303ada72010-10-27 09:33:13 +00005709static MaybeObject* Runtime_StringCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005710 NoHandleAllocation ha;
5711 ASSERT(args.length() == 2);
5712
5713 CONVERT_CHECKED(String, x, args[0]);
5714 CONVERT_CHECKED(String, y, args[1]);
5715
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005716 Counters::string_compare_runtime.Increment();
5717
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005718 // A few fast case tests before we flatten.
5719 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005720 if (y->length() == 0) {
5721 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005722 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005723 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005724 return Smi::FromInt(LESS);
5725 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005726
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005727 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005728 if (d < 0) return Smi::FromInt(LESS);
5729 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005730
lrn@chromium.org303ada72010-10-27 09:33:13 +00005731 Object* obj;
5732 { MaybeObject* maybe_obj = Heap::PrepareForCompare(x);
5733 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5734 }
5735 { MaybeObject* maybe_obj = Heap::PrepareForCompare(y);
5736 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5737 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005738
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005739 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
5740 : StringInputBufferCompare(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005741}
5742
5743
lrn@chromium.org303ada72010-10-27 09:33:13 +00005744static MaybeObject* Runtime_Math_acos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005745 NoHandleAllocation ha;
5746 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005747 Counters::math_acos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005748
5749 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005750 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005751}
5752
5753
lrn@chromium.org303ada72010-10-27 09:33:13 +00005754static MaybeObject* Runtime_Math_asin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005755 NoHandleAllocation ha;
5756 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005757 Counters::math_asin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005758
5759 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005760 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005761}
5762
5763
lrn@chromium.org303ada72010-10-27 09:33:13 +00005764static MaybeObject* Runtime_Math_atan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005765 NoHandleAllocation ha;
5766 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005767 Counters::math_atan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005768
5769 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005770 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005771}
5772
5773
lrn@chromium.org303ada72010-10-27 09:33:13 +00005774static MaybeObject* Runtime_Math_atan2(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005775 NoHandleAllocation ha;
5776 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005777 Counters::math_atan2.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005778
5779 CONVERT_DOUBLE_CHECKED(x, args[0]);
5780 CONVERT_DOUBLE_CHECKED(y, args[1]);
5781 double result;
5782 if (isinf(x) && isinf(y)) {
5783 // Make sure that the result in case of two infinite arguments
5784 // is a multiple of Pi / 4. The sign of the result is determined
5785 // by the first argument (x) and the sign of the second argument
5786 // determines the multiplier: one or three.
5787 static double kPiDividedBy4 = 0.78539816339744830962;
5788 int multiplier = (x < 0) ? -1 : 1;
5789 if (y < 0) multiplier *= 3;
5790 result = multiplier * kPiDividedBy4;
5791 } else {
5792 result = atan2(x, y);
5793 }
5794 return Heap::AllocateHeapNumber(result);
5795}
5796
5797
lrn@chromium.org303ada72010-10-27 09:33:13 +00005798static MaybeObject* Runtime_Math_ceil(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005799 NoHandleAllocation ha;
5800 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005801 Counters::math_ceil.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005802
5803 CONVERT_DOUBLE_CHECKED(x, args[0]);
5804 return Heap::NumberFromDouble(ceiling(x));
5805}
5806
5807
lrn@chromium.org303ada72010-10-27 09:33:13 +00005808static MaybeObject* Runtime_Math_cos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005809 NoHandleAllocation ha;
5810 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005811 Counters::math_cos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005812
5813 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005814 return TranscendentalCache::Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005815}
5816
5817
lrn@chromium.org303ada72010-10-27 09:33:13 +00005818static MaybeObject* Runtime_Math_exp(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005819 NoHandleAllocation ha;
5820 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005821 Counters::math_exp.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005822
5823 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005824 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005825}
5826
5827
lrn@chromium.org303ada72010-10-27 09:33:13 +00005828static MaybeObject* Runtime_Math_floor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005829 NoHandleAllocation ha;
5830 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005831 Counters::math_floor.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005832
5833 CONVERT_DOUBLE_CHECKED(x, args[0]);
5834 return Heap::NumberFromDouble(floor(x));
5835}
5836
5837
lrn@chromium.org303ada72010-10-27 09:33:13 +00005838static MaybeObject* Runtime_Math_log(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005839 NoHandleAllocation ha;
5840 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005841 Counters::math_log.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005842
5843 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005844 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005845}
5846
5847
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005848// Helper function to compute x^y, where y is known to be an
5849// integer. Uses binary decomposition to limit the number of
5850// multiplications; see the discussion in "Hacker's Delight" by Henry
5851// S. Warren, Jr., figure 11-6, page 213.
5852static double powi(double x, int y) {
5853 ASSERT(y != kMinInt);
5854 unsigned n = (y < 0) ? -y : y;
5855 double m = x;
5856 double p = 1;
5857 while (true) {
5858 if ((n & 1) != 0) p *= m;
5859 n >>= 1;
5860 if (n == 0) {
5861 if (y < 0) {
5862 // Unfortunately, we have to be careful when p has reached
5863 // infinity in the computation, because sometimes the higher
5864 // internal precision in the pow() implementation would have
5865 // given us a finite p. This happens very rarely.
5866 double result = 1.0 / p;
5867 return (result == 0 && isinf(p))
5868 ? pow(x, static_cast<double>(y)) // Avoid pow(double, int).
5869 : result;
5870 } else {
5871 return p;
5872 }
5873 }
5874 m *= m;
5875 }
5876}
5877
5878
lrn@chromium.org303ada72010-10-27 09:33:13 +00005879static MaybeObject* Runtime_Math_pow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005880 NoHandleAllocation ha;
5881 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005882 Counters::math_pow.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005883
5884 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005885
5886 // If the second argument is a smi, it is much faster to call the
5887 // custom powi() function than the generic pow().
5888 if (args[1]->IsSmi()) {
5889 int y = Smi::cast(args[1])->value();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005890 return Heap::NumberFromDouble(powi(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005891 }
5892
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005893 CONVERT_DOUBLE_CHECKED(y, args[1]);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00005894
5895 if (!isinf(x)) {
5896 if (y == 0.5) {
5897 // It's not uncommon to use Math.pow(x, 0.5) to compute the
5898 // square root of a number. To speed up such computations, we
5899 // explictly check for this case and use the sqrt() function
5900 // which is faster than pow().
5901 return Heap::AllocateHeapNumber(sqrt(x));
5902 } else if (y == -0.5) {
5903 // Optimized using Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5).
5904 return Heap::AllocateHeapNumber(1.0 / sqrt(x));
5905 }
5906 }
5907
5908 if (y == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005909 return Smi::FromInt(1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005910 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
5911 return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005912 } else {
5913 return Heap::AllocateHeapNumber(pow(x, y));
5914 }
5915}
5916
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005917// Fast version of Math.pow if we know that y is not an integer and
5918// y is not -0.5 or 0.5. Used as slowcase from codegen.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005919static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005920 NoHandleAllocation ha;
5921 ASSERT(args.length() == 2);
5922 CONVERT_DOUBLE_CHECKED(x, args[0]);
5923 CONVERT_DOUBLE_CHECKED(y, args[1]);
5924 if (y == 0) {
5925 return Smi::FromInt(1);
5926 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
5927 return Heap::nan_value();
5928 } else {
5929 return Heap::AllocateHeapNumber(pow(x, y));
5930 }
5931}
5932
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005933
lrn@chromium.org303ada72010-10-27 09:33:13 +00005934static MaybeObject* Runtime_RoundNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005935 NoHandleAllocation ha;
5936 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005937 Counters::math_round.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005938
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00005939 if (!args[0]->IsHeapNumber()) {
5940 // Must be smi. Return the argument unchanged for all the other types
5941 // to make fuzz-natives test happy.
5942 return args[0];
5943 }
5944
5945 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
5946
5947 double value = number->value();
5948 int exponent = number->get_exponent();
5949 int sign = number->get_sign();
5950
5951 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
5952 // should be rounded to 2^30, which is not smi.
5953 if (!sign && exponent <= kSmiValueSize - 3) {
5954 return Smi::FromInt(static_cast<int>(value + 0.5));
5955 }
5956
5957 // If the magnitude is big enough, there's no place for fraction part. If we
5958 // try to add 0.5 to this number, 1.0 will be added instead.
5959 if (exponent >= 52) {
5960 return number;
5961 }
5962
5963 if (sign && value >= -0.5) return Heap::minus_zero_value();
5964
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005965 // Do not call NumberFromDouble() to avoid extra checks.
5966 return Heap::AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005967}
5968
5969
lrn@chromium.org303ada72010-10-27 09:33:13 +00005970static MaybeObject* Runtime_Math_sin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005971 NoHandleAllocation ha;
5972 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005973 Counters::math_sin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005974
5975 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005976 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005977}
5978
5979
lrn@chromium.org303ada72010-10-27 09:33:13 +00005980static MaybeObject* Runtime_Math_sqrt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005981 NoHandleAllocation ha;
5982 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005983 Counters::math_sqrt.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005984
5985 CONVERT_DOUBLE_CHECKED(x, args[0]);
5986 return Heap::AllocateHeapNumber(sqrt(x));
5987}
5988
5989
lrn@chromium.org303ada72010-10-27 09:33:13 +00005990static MaybeObject* Runtime_Math_tan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005991 NoHandleAllocation ha;
5992 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005993 Counters::math_tan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005994
5995 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005996 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005997}
5998
5999
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006000static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006001 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6002 181, 212, 243, 273, 304, 334};
6003 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6004 182, 213, 244, 274, 305, 335};
6005
6006 year += month / 12;
6007 month %= 12;
6008 if (month < 0) {
6009 year--;
6010 month += 12;
6011 }
6012
6013 ASSERT(month >= 0);
6014 ASSERT(month < 12);
6015
6016 // year_delta is an arbitrary number such that:
6017 // a) year_delta = -1 (mod 400)
6018 // b) year + year_delta > 0 for years in the range defined by
6019 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6020 // Jan 1 1970. This is required so that we don't run into integer
6021 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006022 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006023 // operations.
6024 static const int year_delta = 399999;
6025 static const int base_day = 365 * (1970 + year_delta) +
6026 (1970 + year_delta) / 4 -
6027 (1970 + year_delta) / 100 +
6028 (1970 + year_delta) / 400;
6029
6030 int year1 = year + year_delta;
6031 int day_from_year = 365 * year1 +
6032 year1 / 4 -
6033 year1 / 100 +
6034 year1 / 400 -
6035 base_day;
6036
6037 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006038 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006039 }
6040
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006041 return day_from_year + day_from_month_leap[month] + day - 1;
6042}
6043
6044
lrn@chromium.org303ada72010-10-27 09:33:13 +00006045static MaybeObject* Runtime_DateMakeDay(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006046 NoHandleAllocation ha;
6047 ASSERT(args.length() == 3);
6048
6049 CONVERT_SMI_CHECKED(year, args[0]);
6050 CONVERT_SMI_CHECKED(month, args[1]);
6051 CONVERT_SMI_CHECKED(date, args[2]);
6052
6053 return Smi::FromInt(MakeDay(year, month, date));
6054}
6055
6056
6057static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6058static const int kDaysIn4Years = 4 * 365 + 1;
6059static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6060static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6061static const int kDays1970to2000 = 30 * 365 + 7;
6062static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6063 kDays1970to2000;
6064static const int kYearsOffset = 400000;
6065
6066static const char kDayInYear[] = {
6067 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6068 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6069 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6070 22, 23, 24, 25, 26, 27, 28,
6071 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6072 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6073 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6074 22, 23, 24, 25, 26, 27, 28, 29, 30,
6075 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6076 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6077 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6078 22, 23, 24, 25, 26, 27, 28, 29, 30,
6079 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6080 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6081 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6082 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
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,
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, 29, 30, 31,
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,
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, 31,
6091
6092 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6093 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6094 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6095 22, 23, 24, 25, 26, 27, 28,
6096 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6097 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6098 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6099 22, 23, 24, 25, 26, 27, 28, 29, 30,
6100 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6101 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6102 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6103 22, 23, 24, 25, 26, 27, 28, 29, 30,
6104 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6105 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6106 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6107 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6108 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6109 22, 23, 24, 25, 26, 27, 28, 29, 30,
6110 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6111 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6112 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6113 22, 23, 24, 25, 26, 27, 28, 29, 30,
6114 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6115 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6116
6117 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6118 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6119 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6120 22, 23, 24, 25, 26, 27, 28, 29,
6121 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6122 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6123 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6124 22, 23, 24, 25, 26, 27, 28, 29, 30,
6125 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6126 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6127 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6128 22, 23, 24, 25, 26, 27, 28, 29, 30,
6129 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6130 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6131 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6132 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6133 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6134 22, 23, 24, 25, 26, 27, 28, 29, 30,
6135 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6136 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6137 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6138 22, 23, 24, 25, 26, 27, 28, 29, 30,
6139 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6140 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6141
6142 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6143 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6144 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6145 22, 23, 24, 25, 26, 27, 28,
6146 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6147 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6148 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6149 22, 23, 24, 25, 26, 27, 28, 29, 30,
6150 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6151 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6152 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6153 22, 23, 24, 25, 26, 27, 28, 29, 30,
6154 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6155 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6156 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6157 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6158 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6159 22, 23, 24, 25, 26, 27, 28, 29, 30,
6160 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6161 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6162 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6163 22, 23, 24, 25, 26, 27, 28, 29, 30,
6164 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6165 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6166
6167static const char kMonthInYear[] = {
6168 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,
6169 0, 0, 0, 0, 0, 0,
6170 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,
6171 1, 1, 1,
6172 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,
6173 2, 2, 2, 2, 2, 2,
6174 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,
6175 3, 3, 3, 3, 3,
6176 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,
6177 4, 4, 4, 4, 4, 4,
6178 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,
6179 5, 5, 5, 5, 5,
6180 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,
6181 6, 6, 6, 6, 6, 6,
6182 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,
6183 7, 7, 7, 7, 7, 7,
6184 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,
6185 8, 8, 8, 8, 8,
6186 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,
6187 9, 9, 9, 9, 9, 9,
6188 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6189 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6190 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6191 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6192
6193 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,
6194 0, 0, 0, 0, 0, 0,
6195 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,
6196 1, 1, 1,
6197 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,
6198 2, 2, 2, 2, 2, 2,
6199 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,
6200 3, 3, 3, 3, 3,
6201 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,
6202 4, 4, 4, 4, 4, 4,
6203 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,
6204 5, 5, 5, 5, 5,
6205 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,
6206 6, 6, 6, 6, 6, 6,
6207 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,
6208 7, 7, 7, 7, 7, 7,
6209 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,
6210 8, 8, 8, 8, 8,
6211 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,
6212 9, 9, 9, 9, 9, 9,
6213 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6214 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6215 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6216 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6217
6218 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,
6219 0, 0, 0, 0, 0, 0,
6220 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,
6221 1, 1, 1, 1,
6222 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,
6223 2, 2, 2, 2, 2, 2,
6224 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,
6225 3, 3, 3, 3, 3,
6226 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,
6227 4, 4, 4, 4, 4, 4,
6228 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,
6229 5, 5, 5, 5, 5,
6230 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,
6231 6, 6, 6, 6, 6, 6,
6232 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,
6233 7, 7, 7, 7, 7, 7,
6234 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,
6235 8, 8, 8, 8, 8,
6236 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,
6237 9, 9, 9, 9, 9, 9,
6238 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6239 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6240 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6241 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6242
6243 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,
6244 0, 0, 0, 0, 0, 0,
6245 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,
6246 1, 1, 1,
6247 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,
6248 2, 2, 2, 2, 2, 2,
6249 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,
6250 3, 3, 3, 3, 3,
6251 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,
6252 4, 4, 4, 4, 4, 4,
6253 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,
6254 5, 5, 5, 5, 5,
6255 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,
6256 6, 6, 6, 6, 6, 6,
6257 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,
6258 7, 7, 7, 7, 7, 7,
6259 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,
6260 8, 8, 8, 8, 8,
6261 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,
6262 9, 9, 9, 9, 9, 9,
6263 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6264 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6265 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6266 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6267
6268
6269// This function works for dates from 1970 to 2099.
6270static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006271 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006272#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006273 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006274#endif
6275
6276 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6277 date %= kDaysIn4Years;
6278
6279 month = kMonthInYear[date];
6280 day = kDayInYear[date];
6281
6282 ASSERT(MakeDay(year, month, day) == save_date);
6283}
6284
6285
6286static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006287 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006288#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006289 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006290#endif
6291
6292 date += kDaysOffset;
6293 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6294 date %= kDaysIn400Years;
6295
6296 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6297
6298 date--;
6299 int yd1 = date / kDaysIn100Years;
6300 date %= kDaysIn100Years;
6301 year += 100 * yd1;
6302
6303 date++;
6304 int yd2 = date / kDaysIn4Years;
6305 date %= kDaysIn4Years;
6306 year += 4 * yd2;
6307
6308 date--;
6309 int yd3 = date / 365;
6310 date %= 365;
6311 year += yd3;
6312
6313 bool is_leap = (!yd1 || yd2) && !yd3;
6314
6315 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006316 ASSERT(is_leap || (date >= 0));
6317 ASSERT((date < 365) || (is_leap && (date < 366)));
6318 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6319 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6320 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006321
6322 if (is_leap) {
6323 day = kDayInYear[2*365 + 1 + date];
6324 month = kMonthInYear[2*365 + 1 + date];
6325 } else {
6326 day = kDayInYear[date];
6327 month = kMonthInYear[date];
6328 }
6329
6330 ASSERT(MakeDay(year, month, day) == save_date);
6331}
6332
6333
6334static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006335 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006336 if (date >= 0 && date < 32 * kDaysIn4Years) {
6337 DateYMDFromTimeAfter1970(date, year, month, day);
6338 } else {
6339 DateYMDFromTimeSlow(date, year, month, day);
6340 }
6341}
6342
6343
lrn@chromium.org303ada72010-10-27 09:33:13 +00006344static MaybeObject* Runtime_DateYMDFromTime(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006345 NoHandleAllocation ha;
6346 ASSERT(args.length() == 2);
6347
6348 CONVERT_DOUBLE_CHECKED(t, args[0]);
6349 CONVERT_CHECKED(JSArray, res_array, args[1]);
6350
6351 int year, month, day;
6352 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
6353
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006354 RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
6355 FixedArray* elms = FixedArray::cast(res_array->elements());
6356 RUNTIME_ASSERT(elms->length() == 3);
6357
6358 elms->set(0, Smi::FromInt(year));
6359 elms->set(1, Smi::FromInt(month));
6360 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006361
6362 return Heap::undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006363}
6364
6365
lrn@chromium.org303ada72010-10-27 09:33:13 +00006366static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006367 NoHandleAllocation ha;
6368 ASSERT(args.length() == 3);
6369
6370 JSFunction* callee = JSFunction::cast(args[0]);
6371 Object** parameters = reinterpret_cast<Object**>(args[1]);
6372 const int length = Smi::cast(args[2])->value();
6373
lrn@chromium.org303ada72010-10-27 09:33:13 +00006374 Object* result;
6375 { MaybeObject* maybe_result = Heap::AllocateArgumentsObject(callee, length);
6376 if (!maybe_result->ToObject(&result)) return maybe_result;
6377 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006378 // Allocate the elements if needed.
6379 if (length > 0) {
6380 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006381 Object* obj;
6382 { MaybeObject* maybe_obj = Heap::AllocateRawFixedArray(length);
6383 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6384 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006385
6386 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006387 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
6388 array->set_map(Heap::fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006389 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006390
6391 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006392 for (int i = 0; i < length; i++) {
6393 array->set(i, *--parameters, mode);
6394 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006395 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006396 }
6397 return result;
6398}
6399
6400
lrn@chromium.org303ada72010-10-27 09:33:13 +00006401static MaybeObject* Runtime_NewClosure(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006402 HandleScope scope;
6403 ASSERT(args.length() == 2);
ager@chromium.org3811b432009-10-28 14:53:37 +00006404 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006405 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006406
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00006407 PretenureFlag pretenure = (context->global_context() == *context)
6408 ? TENURED // Allocate global closures in old space.
6409 : NOT_TENURED; // Allocate local closures in new space.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006410 Handle<JSFunction> result =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006411 Factory::NewFunctionFromSharedFunctionInfo(shared, context, pretenure);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006412 return *result;
6413}
6414
lrn@chromium.org303ada72010-10-27 09:33:13 +00006415static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006416 HandleScope scope;
6417 ASSERT(args.length() == 2);
6418 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6419 CONVERT_ARG_CHECKED(JSArray, params, 1);
6420
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006421 RUNTIME_ASSERT(params->HasFastElements());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006422 FixedArray* fixed = FixedArray::cast(params->elements());
6423
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006424 int fixed_length = Smi::cast(params->length())->value();
6425 SmartPointer<Object**> param_data(NewArray<Object**>(fixed_length));
6426 for (int i = 0; i < fixed_length; i++) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006427 Handle<Object> val = Handle<Object>(fixed->get(i));
6428 param_data[i] = val.location();
6429 }
6430
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006431 bool exception = false;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006432 Handle<Object> result = Execution::New(
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006433 function, fixed_length, *param_data, &exception);
6434 if (exception) {
6435 return Failure::Exception();
6436 }
6437 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006438 return *result;
6439}
6440
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006441
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006442static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
ager@chromium.org5c838252010-02-19 08:53:10 +00006443 Handle<Object> prototype = Factory::null_value();
6444 if (function->has_instance_prototype()) {
6445 prototype = Handle<Object>(function->instance_prototype());
6446 }
6447 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006448 ConstructStubCompiler compiler;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006449 MaybeObject* code = compiler.CompileConstructStub(function->shared());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006450 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006451 function->shared()->set_construct_stub(
6452 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006453 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006454 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006455}
6456
6457
lrn@chromium.org303ada72010-10-27 09:33:13 +00006458static MaybeObject* Runtime_NewObject(Arguments args) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006459 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006460 ASSERT(args.length() == 1);
6461
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006462 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006463
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006464 // If the constructor isn't a proper function we throw a type error.
6465 if (!constructor->IsJSFunction()) {
6466 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6467 Handle<Object> type_error =
6468 Factory::NewTypeError("not_constructor", arguments);
6469 return Top::Throw(*type_error);
6470 }
6471
6472 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006473
6474 // If function should not have prototype, construction is not allowed. In this
6475 // case generated code bailouts here, since function has no initial_map.
6476 if (!function->should_have_prototype()) {
6477 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6478 Handle<Object> type_error =
6479 Factory::NewTypeError("not_constructor", arguments);
6480 return Top::Throw(*type_error);
6481 }
6482
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006483#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006484 // Handle stepping into constructors if step into is active.
6485 if (Debug::StepInActive()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006486 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006487 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006488#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006489
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006490 if (function->has_initial_map()) {
6491 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006492 // The 'Function' function ignores the receiver object when
6493 // called using 'new' and creates a new JSFunction object that
6494 // is returned. The receiver object is only used for error
6495 // reporting if an error occurs when constructing the new
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006496 // JSFunction. Factory::NewJSObject() should not be used to
6497 // allocate JSFunctions since it does not properly initialize
6498 // the shared part of the function. Since the receiver is
6499 // ignored anyway, we use the global object as the receiver
6500 // instead of a new JSFunction object. This way, errors are
6501 // reported the same way whether or not 'Function' is called
6502 // using 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006503 return Top::context()->global();
6504 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006505 }
6506
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006507 // The function should be compiled for the optimization hints to be available.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006508 Handle<SharedFunctionInfo> shared(function->shared());
6509 EnsureCompiled(shared, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006510
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006511 if (!function->has_initial_map() &&
6512 shared->IsInobjectSlackTrackingInProgress()) {
6513 // The tracking is already in progress for another function. We can only
6514 // track one initial_map at a time, so we force the completion before the
6515 // function is called as a constructor for the first time.
6516 shared->CompleteInobjectSlackTracking();
6517 TrySettingInlineConstructStub(function);
6518 }
6519
6520 bool first_allocation = !shared->live_objects_may_exist();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006521 Handle<JSObject> result = Factory::NewJSObject(function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006522 // Delay setting the stub if inobject slack tracking is in progress.
6523 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
6524 TrySettingInlineConstructStub(function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006525 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006526
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006527 Counters::constructed_objects.Increment();
6528 Counters::constructed_objects_runtime.Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006529
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006530 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006531}
6532
6533
lrn@chromium.org303ada72010-10-27 09:33:13 +00006534static MaybeObject* Runtime_FinalizeInstanceSize(Arguments args) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006535 HandleScope scope;
6536 ASSERT(args.length() == 1);
6537
6538 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6539 function->shared()->CompleteInobjectSlackTracking();
6540 TrySettingInlineConstructStub(function);
6541
6542 return Heap::undefined_value();
6543}
6544
6545
lrn@chromium.org303ada72010-10-27 09:33:13 +00006546static MaybeObject* Runtime_LazyCompile(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006547 HandleScope scope;
6548 ASSERT(args.length() == 1);
6549
6550 Handle<JSFunction> function = args.at<JSFunction>(0);
6551#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00006552 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006553 PrintF("[lazy: ");
6554 function->shared()->name()->Print();
6555 PrintF("]\n");
6556 }
6557#endif
6558
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006559 // Compile the target function. Here we compile using CompileLazyInLoop in
6560 // order to get the optimized version. This helps code like delta-blue
6561 // that calls performance-critical routines through constructors. A
6562 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
6563 // direct call. Since the in-loop tracking takes place through CallICs
6564 // this means that things called through constructors are never known to
6565 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006566 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006567 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006568 return Failure::Exception();
6569 }
6570
6571 return function->code();
6572}
6573
6574
lrn@chromium.org303ada72010-10-27 09:33:13 +00006575static MaybeObject* Runtime_GetFunctionDelegate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006576 HandleScope scope;
6577 ASSERT(args.length() == 1);
6578 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6579 return *Execution::GetFunctionDelegate(args.at<Object>(0));
6580}
6581
6582
lrn@chromium.org303ada72010-10-27 09:33:13 +00006583static MaybeObject* Runtime_GetConstructorDelegate(Arguments args) {
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006584 HandleScope scope;
6585 ASSERT(args.length() == 1);
6586 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6587 return *Execution::GetConstructorDelegate(args.at<Object>(0));
6588}
6589
6590
lrn@chromium.org303ada72010-10-27 09:33:13 +00006591static MaybeObject* Runtime_NewContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006592 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00006593 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006594
kasper.lund7276f142008-07-30 08:49:36 +00006595 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00006596 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00006597 Object* result;
6598 { MaybeObject* maybe_result = Heap::AllocateFunctionContext(length, function);
6599 if (!maybe_result->ToObject(&result)) return maybe_result;
6600 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006601
6602 Top::set_context(Context::cast(result));
6603
kasper.lund7276f142008-07-30 08:49:36 +00006604 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006605}
6606
lrn@chromium.org303ada72010-10-27 09:33:13 +00006607
6608MUST_USE_RESULT static MaybeObject* PushContextHelper(Object* object,
6609 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006610 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006611 Object* js_object = object;
6612 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006613 MaybeObject* maybe_js_object = js_object->ToObject();
6614 if (!maybe_js_object->ToObject(&js_object)) {
6615 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
6616 return maybe_js_object;
6617 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006618 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006619 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006620 Handle<Object> result =
6621 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
6622 return Top::Throw(*result);
6623 }
6624 }
6625
lrn@chromium.org303ada72010-10-27 09:33:13 +00006626 Object* result;
6627 { MaybeObject* maybe_result =
6628 Heap::AllocateWithContext(Top::context(),
6629 JSObject::cast(js_object),
6630 is_catch_context);
6631 if (!maybe_result->ToObject(&result)) return maybe_result;
6632 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006633
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006634 Context* context = Context::cast(result);
6635 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006636
kasper.lund7276f142008-07-30 08:49:36 +00006637 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006638}
6639
6640
lrn@chromium.org303ada72010-10-27 09:33:13 +00006641static MaybeObject* Runtime_PushContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006642 NoHandleAllocation ha;
6643 ASSERT(args.length() == 1);
6644 return PushContextHelper(args[0], false);
6645}
6646
6647
lrn@chromium.org303ada72010-10-27 09:33:13 +00006648static MaybeObject* Runtime_PushCatchContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006649 NoHandleAllocation ha;
6650 ASSERT(args.length() == 1);
6651 return PushContextHelper(args[0], true);
6652}
6653
6654
lrn@chromium.org303ada72010-10-27 09:33:13 +00006655static MaybeObject* Runtime_LookupContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006656 HandleScope scope;
6657 ASSERT(args.length() == 2);
6658
6659 CONVERT_ARG_CHECKED(Context, context, 0);
6660 CONVERT_ARG_CHECKED(String, name, 1);
6661
6662 int index;
6663 PropertyAttributes attributes;
6664 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006665 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006666 context->Lookup(name, flags, &index, &attributes);
6667
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006668 if (index < 0 && !holder.is_null()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006669 ASSERT(holder->IsJSObject());
6670 return *holder;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006671 }
6672
6673 // No intermediate context found. Use global object by default.
6674 return Top::context()->global();
6675}
6676
6677
ager@chromium.orga1645e22009-09-09 19:27:10 +00006678// A mechanism to return a pair of Object pointers in registers (if possible).
6679// How this is achieved is calling convention-dependent.
6680// All currently supported x86 compiles uses calling conventions that are cdecl
6681// variants where a 64-bit value is returned in two 32-bit registers
6682// (edx:eax on ia32, r1:r0 on ARM).
6683// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
6684// In Win64 calling convention, a struct of two pointers is returned in memory,
6685// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006686#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006687struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006688 MaybeObject* x;
6689 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006690};
ager@chromium.orga1645e22009-09-09 19:27:10 +00006691
lrn@chromium.org303ada72010-10-27 09:33:13 +00006692static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006693 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00006694 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
6695 // In Win64 they are assigned to a hidden first argument.
6696 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006697}
6698#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006699typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006700static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006701 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006702 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006703}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006704#endif
6705
6706
lrn@chromium.org303ada72010-10-27 09:33:13 +00006707static inline MaybeObject* Unhole(MaybeObject* x,
6708 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006709 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
6710 USE(attributes);
6711 return x->IsTheHole() ? Heap::undefined_value() : x;
6712}
6713
6714
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006715static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
6716 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006717 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006718 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006719 JSFunction* context_extension_function =
6720 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006721 // If the holder isn't a context extension object, we just return it
6722 // as the receiver. This allows arguments objects to be used as
6723 // receivers, but only if they are put in the context scope chain
6724 // explicitly via a with-statement.
6725 Object* constructor = holder->map()->constructor();
6726 if (constructor != context_extension_function) return holder;
6727 // Fall back to using the global object as the receiver if the
6728 // property turns out to be a local variable allocated in a context
6729 // extension object - introduced via eval.
6730 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006731}
6732
6733
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006734static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006735 HandleScope scope;
ager@chromium.orga1645e22009-09-09 19:27:10 +00006736 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006737
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006738 if (!args[0]->IsContext() || !args[1]->IsString()) {
ager@chromium.org3e875802009-06-29 08:26:34 +00006739 return MakePair(Top::ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006740 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006741 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006742 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006743
6744 int index;
6745 PropertyAttributes attributes;
6746 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006747 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006748 context->Lookup(name, flags, &index, &attributes);
6749
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006750 // If the index is non-negative, the slot has been found in a local
6751 // variable or a parameter. Read it from the context object or the
6752 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006753 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006754 // If the "property" we were looking for is a local variable or an
6755 // argument in a context, the receiver is the global object; see
6756 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
6757 JSObject* receiver = Top::context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00006758 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006759 ? Context::cast(*holder)->get(index)
6760 : JSObject::cast(*holder)->GetElement(index);
6761 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006762 }
6763
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006764 // If the holder is found, we read the property from it.
6765 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006766 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006767 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006768 JSObject* receiver;
6769 if (object->IsGlobalObject()) {
6770 receiver = GlobalObject::cast(object)->global_receiver();
6771 } else if (context->is_exception_holder(*holder)) {
6772 receiver = Top::context()->global()->global_receiver();
6773 } else {
6774 receiver = ComputeReceiverForNonGlobal(object);
6775 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006776 // No need to unhole the value here. This is taken care of by the
6777 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006778 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006779 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006780 }
6781
6782 if (throw_error) {
6783 // The property doesn't exist - throw exception.
6784 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006785 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006786 return MakePair(Top::Throw(*reference_error), NULL);
6787 } else {
6788 // The property doesn't exist - return undefined
6789 return MakePair(Heap::undefined_value(), Heap::undefined_value());
6790 }
6791}
6792
6793
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006794static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006795 return LoadContextSlotHelper(args, true);
6796}
6797
6798
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006799static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006800 return LoadContextSlotHelper(args, false);
6801}
6802
6803
lrn@chromium.org303ada72010-10-27 09:33:13 +00006804static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006805 HandleScope scope;
6806 ASSERT(args.length() == 3);
6807
6808 Handle<Object> value(args[0]);
6809 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006810 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006811
6812 int index;
6813 PropertyAttributes attributes;
6814 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006815 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006816 context->Lookup(name, flags, &index, &attributes);
6817
6818 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006819 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006820 // Ignore if read_only variable.
6821 if ((attributes & READ_ONLY) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006822 Handle<Context>::cast(holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006823 }
6824 } else {
6825 ASSERT((attributes & READ_ONLY) == 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006826 Handle<JSObject>::cast(holder)->SetElement(index, *value)->
6827 ToObjectUnchecked();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006828 }
6829 return *value;
6830 }
6831
6832 // Slow case: The property is not in a FixedArray context.
6833 // It is either in an JSObject extension context or it was not found.
6834 Handle<JSObject> context_ext;
6835
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006836 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006837 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006838 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006839 } else {
6840 // The property was not found. It needs to be stored in the global context.
6841 ASSERT(attributes == ABSENT);
6842 attributes = NONE;
6843 context_ext = Handle<JSObject>(Top::context()->global());
6844 }
6845
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006846 // Set the property, but ignore if read_only variable on the context
6847 // extension object itself.
6848 if ((attributes & READ_ONLY) == 0 ||
6849 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006850 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
6851 if (set.is_null()) {
6852 // Failure::Exception is converted to a null handle in the
6853 // handle-based methods such as SetProperty. We therefore need
6854 // to convert null handles back to exceptions.
6855 ASSERT(Top::has_pending_exception());
6856 return Failure::Exception();
6857 }
6858 }
6859 return *value;
6860}
6861
6862
lrn@chromium.org303ada72010-10-27 09:33:13 +00006863static MaybeObject* Runtime_Throw(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006864 HandleScope scope;
6865 ASSERT(args.length() == 1);
6866
6867 return Top::Throw(args[0]);
6868}
6869
6870
lrn@chromium.org303ada72010-10-27 09:33:13 +00006871static MaybeObject* Runtime_ReThrow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006872 HandleScope scope;
6873 ASSERT(args.length() == 1);
6874
6875 return Top::ReThrow(args[0]);
6876}
6877
6878
lrn@chromium.org303ada72010-10-27 09:33:13 +00006879static MaybeObject* Runtime_PromoteScheduledException(Arguments args) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006880 ASSERT_EQ(0, args.length());
6881 return Top::PromoteScheduledException();
6882}
6883
6884
lrn@chromium.org303ada72010-10-27 09:33:13 +00006885static MaybeObject* Runtime_ThrowReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006886 HandleScope scope;
6887 ASSERT(args.length() == 1);
6888
6889 Handle<Object> name(args[0]);
6890 Handle<Object> reference_error =
6891 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
6892 return Top::Throw(*reference_error);
6893}
6894
6895
lrn@chromium.org303ada72010-10-27 09:33:13 +00006896static MaybeObject* Runtime_StackOverflow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006897 NoHandleAllocation na;
6898 return Top::StackOverflow();
6899}
6900
6901
lrn@chromium.org303ada72010-10-27 09:33:13 +00006902static MaybeObject* Runtime_StackGuard(Arguments args) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00006903 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006904
6905 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00006906 if (StackGuard::IsStackOverflow()) {
6907 return Runtime_StackOverflow(args);
6908 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006909
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006910 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006911}
6912
6913
6914// NOTE: These PrintXXX functions are defined for all builds (not just
6915// DEBUG builds) because we may want to be able to trace function
6916// calls in all modes.
6917static void PrintString(String* str) {
6918 // not uncommon to have empty strings
6919 if (str->length() > 0) {
6920 SmartPointer<char> s =
6921 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
6922 PrintF("%s", *s);
6923 }
6924}
6925
6926
6927static void PrintObject(Object* obj) {
6928 if (obj->IsSmi()) {
6929 PrintF("%d", Smi::cast(obj)->value());
6930 } else if (obj->IsString() || obj->IsSymbol()) {
6931 PrintString(String::cast(obj));
6932 } else if (obj->IsNumber()) {
6933 PrintF("%g", obj->Number());
6934 } else if (obj->IsFailure()) {
6935 PrintF("<failure>");
6936 } else if (obj->IsUndefined()) {
6937 PrintF("<undefined>");
6938 } else if (obj->IsNull()) {
6939 PrintF("<null>");
6940 } else if (obj->IsTrue()) {
6941 PrintF("<true>");
6942 } else if (obj->IsFalse()) {
6943 PrintF("<false>");
6944 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006945 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006946 }
6947}
6948
6949
6950static int StackSize() {
6951 int n = 0;
6952 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
6953 return n;
6954}
6955
6956
6957static void PrintTransition(Object* result) {
6958 // indentation
6959 { const int nmax = 80;
6960 int n = StackSize();
6961 if (n <= nmax)
6962 PrintF("%4d:%*s", n, n, "");
6963 else
6964 PrintF("%4d:%*s", n, nmax, "...");
6965 }
6966
6967 if (result == NULL) {
6968 // constructor calls
6969 JavaScriptFrameIterator it;
6970 JavaScriptFrame* frame = it.frame();
6971 if (frame->IsConstructor()) PrintF("new ");
6972 // function name
6973 Object* fun = frame->function();
6974 if (fun->IsJSFunction()) {
6975 PrintObject(JSFunction::cast(fun)->shared()->name());
6976 } else {
6977 PrintObject(fun);
6978 }
6979 // function arguments
6980 // (we are intentionally only printing the actually
6981 // supplied parameters, not all parameters required)
6982 PrintF("(this=");
6983 PrintObject(frame->receiver());
6984 const int length = frame->GetProvidedParametersCount();
6985 for (int i = 0; i < length; i++) {
6986 PrintF(", ");
6987 PrintObject(frame->GetParameter(i));
6988 }
6989 PrintF(") {\n");
6990
6991 } else {
6992 // function result
6993 PrintF("} -> ");
6994 PrintObject(result);
6995 PrintF("\n");
6996 }
6997}
6998
6999
lrn@chromium.org303ada72010-10-27 09:33:13 +00007000static MaybeObject* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007001 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007002 NoHandleAllocation ha;
7003 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007004 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007005}
7006
7007
lrn@chromium.org303ada72010-10-27 09:33:13 +00007008static MaybeObject* Runtime_TraceExit(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007009 NoHandleAllocation ha;
7010 PrintTransition(args[0]);
7011 return args[0]; // return TOS
7012}
7013
7014
lrn@chromium.org303ada72010-10-27 09:33:13 +00007015static MaybeObject* Runtime_DebugPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007016 NoHandleAllocation ha;
7017 ASSERT(args.length() == 1);
7018
7019#ifdef DEBUG
7020 if (args[0]->IsString()) {
7021 // If we have a string, assume it's a code "marker"
7022 // and print some interesting cpu debugging info.
7023 JavaScriptFrameIterator it;
7024 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007025 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
7026 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007027 } else {
7028 PrintF("DebugPrint: ");
7029 }
7030 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007031 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007032 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007033 HeapObject::cast(args[0])->map()->Print();
7034 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007035#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007036 // ShortPrint is available in release mode. Print is not.
7037 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007038#endif
7039 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00007040 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007041
7042 return args[0]; // return TOS
7043}
7044
7045
lrn@chromium.org303ada72010-10-27 09:33:13 +00007046static MaybeObject* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007047 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007048 NoHandleAllocation ha;
7049 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007050 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007051}
7052
7053
lrn@chromium.org303ada72010-10-27 09:33:13 +00007054static MaybeObject* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007055 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007056 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007057
7058 // According to ECMA-262, section 15.9.1, page 117, the precision of
7059 // the number in a Date object representing a particular instant in
7060 // time is milliseconds. Therefore, we floor the result of getting
7061 // the OS time.
7062 double millis = floor(OS::TimeCurrentMillis());
7063 return Heap::NumberFromDouble(millis);
7064}
7065
7066
lrn@chromium.org303ada72010-10-27 09:33:13 +00007067static MaybeObject* Runtime_DateParseString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007068 HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007069 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007070
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007071 CONVERT_ARG_CHECKED(String, str, 0);
7072 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007073
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007074 CONVERT_ARG_CHECKED(JSArray, output, 1);
7075 RUNTIME_ASSERT(output->HasFastElements());
7076
7077 AssertNoAllocation no_allocation;
7078
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007079 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007080 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
7081 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007082 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007083 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007084 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007085 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007086 result = DateParser::Parse(str->ToUC16Vector(), output_array);
7087 }
7088
7089 if (result) {
7090 return *output;
7091 } else {
7092 return Heap::null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007093 }
7094}
7095
7096
lrn@chromium.org303ada72010-10-27 09:33:13 +00007097static MaybeObject* Runtime_DateLocalTimezone(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007098 NoHandleAllocation ha;
7099 ASSERT(args.length() == 1);
7100
7101 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00007102 const char* zone = OS::LocalTimezone(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007103 return Heap::AllocateStringFromUtf8(CStrVector(zone));
7104}
7105
7106
lrn@chromium.org303ada72010-10-27 09:33:13 +00007107static MaybeObject* Runtime_DateLocalTimeOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007108 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007109 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007110
7111 return Heap::NumberFromDouble(OS::LocalTimeOffset());
7112}
7113
7114
lrn@chromium.org303ada72010-10-27 09:33:13 +00007115static MaybeObject* Runtime_DateDaylightSavingsOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007116 NoHandleAllocation ha;
7117 ASSERT(args.length() == 1);
7118
7119 CONVERT_DOUBLE_CHECKED(x, args[0]);
7120 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
7121}
7122
7123
lrn@chromium.org303ada72010-10-27 09:33:13 +00007124static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007125 ASSERT(args.length() == 1);
7126 Object* global = args[0];
7127 if (!global->IsJSGlobalObject()) return Heap::null_value();
7128 return JSGlobalObject::cast(global)->global_receiver();
7129}
7130
7131
lrn@chromium.org303ada72010-10-27 09:33:13 +00007132static MaybeObject* Runtime_CompileString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007133 HandleScope scope;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007134 ASSERT_EQ(2, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007135 CONVERT_ARG_CHECKED(String, source, 0);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007136 CONVERT_ARG_CHECKED(Oddball, is_json, 1)
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007137
ager@chromium.org381abbb2009-02-25 13:23:22 +00007138 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007139 Handle<Context> context(Top::context()->global_context());
ager@chromium.orgadd848f2009-08-13 12:44:13 +00007140 Compiler::ValidationState validate = (is_json->IsTrue())
7141 ? Compiler::VALIDATE_JSON : Compiler::DONT_VALIDATE_JSON;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007142 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
7143 context,
7144 true,
7145 validate);
7146 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007147 Handle<JSFunction> fun =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007148 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007149 return *fun;
7150}
7151
7152
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007153static ObjectPair CompileGlobalEval(Handle<String> source,
7154 Handle<Object> receiver) {
7155 // Deal with a normal eval call with a string argument. Compile it
7156 // and return the compiled function bound in the local context.
7157 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
7158 source,
7159 Handle<Context>(Top::context()),
7160 Top::context()->IsGlobalContext(),
7161 Compiler::DONT_VALIDATE_JSON);
7162 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
7163 Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
7164 shared,
7165 Handle<Context>(Top::context()),
7166 NOT_TENURED);
7167 return MakePair(*compiled, *receiver);
7168}
7169
7170
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007171static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
7172 ASSERT(args.length() == 3);
7173 if (!args[0]->IsJSFunction()) {
7174 return MakePair(Top::ThrowIllegalOperation(), NULL);
7175 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007176
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007177 HandleScope scope;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007178 Handle<JSFunction> callee = args.at<JSFunction>(0);
7179 Handle<Object> receiver; // Will be overwritten.
7180
7181 // Compute the calling context.
7182 Handle<Context> context = Handle<Context>(Top::context());
7183#ifdef DEBUG
7184 // Make sure Top::context() agrees with the old code that traversed
7185 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007186 StackFrameLocator locator;
7187 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007188 ASSERT(Context::cast(frame->context()) == *context);
7189#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007190
7191 // Find where the 'eval' symbol is bound. It is unaliased only if
7192 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007193 int index = -1;
7194 PropertyAttributes attributes = ABSENT;
7195 while (true) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007196 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
7197 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007198 // Stop search when eval is found or when the global context is
7199 // reached.
7200 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007201 if (context->is_function_context()) {
7202 context = Handle<Context>(Context::cast(context->closure()->context()));
7203 } else {
7204 context = Handle<Context>(context->previous());
7205 }
7206 }
7207
iposva@chromium.org245aa852009-02-10 00:49:54 +00007208 // If eval could not be resolved, it has been deleted and we need to
7209 // throw a reference error.
7210 if (attributes == ABSENT) {
7211 Handle<Object> name = Factory::eval_symbol();
7212 Handle<Object> reference_error =
7213 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007214 return MakePair(Top::Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007215 }
7216
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007217 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007218 // 'eval' is not bound in the global context. Just call the function
7219 // with the given arguments. This is not necessarily the global eval.
7220 if (receiver->IsContext()) {
7221 context = Handle<Context>::cast(receiver);
7222 receiver = Handle<Object>(context->get(index));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007223 } else if (receiver->IsJSContextExtensionObject()) {
7224 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007225 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007226 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007227 }
7228
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007229 // 'eval' is bound in the global context, but it may have been overwritten.
7230 // Compare it to the builtin 'GlobalEval' function to make sure.
7231 if (*callee != Top::global_context()->global_eval_fun() ||
7232 !args[1]->IsString()) {
7233 return MakePair(*callee, Top::context()->global()->global_receiver());
7234 }
7235
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007236 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
7237}
7238
7239
7240static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
7241 ASSERT(args.length() == 3);
7242 if (!args[0]->IsJSFunction()) {
7243 return MakePair(Top::ThrowIllegalOperation(), NULL);
7244 }
7245
7246 HandleScope scope;
7247 Handle<JSFunction> callee = args.at<JSFunction>(0);
7248
7249 // 'eval' is bound in the global context, but it may have been overwritten.
7250 // Compare it to the builtin 'GlobalEval' function to make sure.
7251 if (*callee != Top::global_context()->global_eval_fun() ||
7252 !args[1]->IsString()) {
7253 return MakePair(*callee, Top::context()->global()->global_receiver());
7254 }
7255
7256 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007257}
7258
7259
lrn@chromium.org303ada72010-10-27 09:33:13 +00007260static MaybeObject* Runtime_SetNewFunctionAttributes(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007261 // This utility adjusts the property attributes for newly created Function
7262 // object ("new Function(...)") by changing the map.
7263 // All it does is changing the prototype property to enumerable
7264 // as specified in ECMA262, 15.3.5.2.
7265 HandleScope scope;
7266 ASSERT(args.length() == 1);
7267 CONVERT_ARG_CHECKED(JSFunction, func, 0);
7268 ASSERT(func->map()->instance_type() ==
7269 Top::function_instance_map()->instance_type());
7270 ASSERT(func->map()->instance_size() ==
7271 Top::function_instance_map()->instance_size());
7272 func->set_map(*Top::function_instance_map());
7273 return *func;
7274}
7275
7276
lrn@chromium.org303ada72010-10-27 09:33:13 +00007277static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007278 // Allocate a block of memory in NewSpace (filled with a filler).
7279 // Use as fallback for allocation in generated code when NewSpace
7280 // is full.
7281 ASSERT(args.length() == 1);
7282 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
7283 int size = size_smi->value();
7284 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
7285 RUNTIME_ASSERT(size > 0);
7286 static const int kMinFreeNewSpaceAfterGC =
7287 Heap::InitialSemiSpaceSize() * 3/4;
7288 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007289 Object* allocation;
7290 { MaybeObject* maybe_allocation = Heap::new_space()->AllocateRaw(size);
7291 if (maybe_allocation->ToObject(&allocation)) {
7292 Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
7293 }
7294 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007295 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007296}
7297
7298
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007299// Push an array unto an array of arrays if it is not already in the
7300// array. Returns true if the element was pushed on the stack and
7301// false otherwise.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007302static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007303 ASSERT(args.length() == 2);
7304 CONVERT_CHECKED(JSArray, array, args[0]);
7305 CONVERT_CHECKED(JSArray, element, args[1]);
7306 RUNTIME_ASSERT(array->HasFastElements());
7307 int length = Smi::cast(array->length())->value();
7308 FixedArray* elements = FixedArray::cast(array->elements());
7309 for (int i = 0; i < length; i++) {
7310 if (elements->get(i) == element) return Heap::false_value();
7311 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007312 Object* obj;
7313 { MaybeObject* maybe_obj = array->SetFastElement(length, element);
7314 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7315 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007316 return Heap::true_value();
7317}
7318
7319
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007320/**
7321 * A simple visitor visits every element of Array's.
7322 * The backend storage can be a fixed array for fast elements case,
7323 * or a dictionary for sparse array. Since Dictionary is a subtype
7324 * of FixedArray, the class can be used by both fast and slow cases.
7325 * The second parameter of the constructor, fast_elements, specifies
7326 * whether the storage is a FixedArray or Dictionary.
7327 *
7328 * An index limit is used to deal with the situation that a result array
7329 * length overflows 32-bit non-negative integer.
7330 */
7331class ArrayConcatVisitor {
7332 public:
7333 ArrayConcatVisitor(Handle<FixedArray> storage,
7334 uint32_t index_limit,
7335 bool fast_elements) :
7336 storage_(storage), index_limit_(index_limit),
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007337 index_offset_(0), fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007338
7339 void visit(uint32_t i, Handle<Object> elm) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007340 if (i >= index_limit_ - index_offset_) return;
7341 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007342
7343 if (fast_elements_) {
7344 ASSERT(index < static_cast<uint32_t>(storage_->length()));
7345 storage_->set(index, *elm);
7346
7347 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007348 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
7349 Handle<NumberDictionary> result =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007350 Factory::DictionaryAtNumberPut(dict, index, elm);
7351 if (!result.is_identical_to(dict))
7352 storage_ = result;
7353 }
7354 }
7355
7356 void increase_index_offset(uint32_t delta) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007357 if (index_limit_ - index_offset_ < delta) {
7358 index_offset_ = index_limit_;
7359 } else {
7360 index_offset_ += delta;
7361 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007362 }
7363
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007364 Handle<FixedArray> storage() { return storage_; }
7365
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007366 private:
7367 Handle<FixedArray> storage_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007368 // Limit on the accepted indices. Elements with indices larger than the
7369 // limit are ignored by the visitor.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007370 uint32_t index_limit_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007371 // Index after last seen index. Always less than or equal to index_limit_.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007372 uint32_t index_offset_;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007373 const bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007374};
7375
7376
ager@chromium.org3811b432009-10-28 14:53:37 +00007377template<class ExternalArrayClass, class ElementType>
7378static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver,
7379 bool elements_are_ints,
7380 bool elements_are_guaranteed_smis,
7381 uint32_t range,
7382 ArrayConcatVisitor* visitor) {
7383 Handle<ExternalArrayClass> array(
7384 ExternalArrayClass::cast(receiver->elements()));
7385 uint32_t len = Min(static_cast<uint32_t>(array->length()), range);
7386
7387 if (visitor != NULL) {
7388 if (elements_are_ints) {
7389 if (elements_are_guaranteed_smis) {
7390 for (uint32_t j = 0; j < len; j++) {
7391 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
7392 visitor->visit(j, e);
7393 }
7394 } else {
7395 for (uint32_t j = 0; j < len; j++) {
7396 int64_t val = static_cast<int64_t>(array->get(j));
7397 if (Smi::IsValid(static_cast<intptr_t>(val))) {
7398 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
7399 visitor->visit(j, e);
7400 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007401 Handle<Object> e =
7402 Factory::NewNumber(static_cast<ElementType>(val));
ager@chromium.org3811b432009-10-28 14:53:37 +00007403 visitor->visit(j, e);
7404 }
7405 }
7406 }
7407 } else {
7408 for (uint32_t j = 0; j < len; j++) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007409 Handle<Object> e = Factory::NewNumber(array->get(j));
ager@chromium.org3811b432009-10-28 14:53:37 +00007410 visitor->visit(j, e);
7411 }
7412 }
7413 }
7414
7415 return len;
7416}
7417
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007418/**
7419 * A helper function that visits elements of a JSObject. Only elements
7420 * whose index between 0 and range (exclusive) are visited.
7421 *
7422 * If the third parameter, visitor, is not NULL, the visitor is called
7423 * with parameters, 'visitor_index_offset + element index' and the element.
7424 *
7425 * It returns the number of visisted elements.
7426 */
7427static uint32_t IterateElements(Handle<JSObject> receiver,
7428 uint32_t range,
7429 ArrayConcatVisitor* visitor) {
7430 uint32_t num_of_elements = 0;
7431
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007432 switch (receiver->GetElementsKind()) {
7433 case JSObject::FAST_ELEMENTS: {
7434 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
7435 uint32_t len = elements->length();
7436 if (range < len) {
7437 len = range;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007438 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007439
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007440 for (uint32_t j = 0; j < len; j++) {
7441 Handle<Object> e(elements->get(j));
7442 if (!e->IsTheHole()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007443 num_of_elements++;
7444 if (visitor) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007445 visitor->visit(j, e);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007446 }
7447 }
7448 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007449 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007450 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007451 case JSObject::PIXEL_ELEMENTS: {
7452 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
7453 uint32_t len = pixels->length();
7454 if (range < len) {
7455 len = range;
7456 }
7457
7458 for (uint32_t j = 0; j < len; j++) {
7459 num_of_elements++;
7460 if (visitor != NULL) {
7461 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
7462 visitor->visit(j, e);
7463 }
7464 }
7465 break;
7466 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007467 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
7468 num_of_elements =
7469 IterateExternalArrayElements<ExternalByteArray, int8_t>(
7470 receiver, true, true, range, visitor);
7471 break;
7472 }
7473 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
7474 num_of_elements =
7475 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
7476 receiver, true, true, range, visitor);
7477 break;
7478 }
7479 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
7480 num_of_elements =
7481 IterateExternalArrayElements<ExternalShortArray, int16_t>(
7482 receiver, true, true, range, visitor);
7483 break;
7484 }
7485 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
7486 num_of_elements =
7487 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
7488 receiver, true, true, range, visitor);
7489 break;
7490 }
7491 case JSObject::EXTERNAL_INT_ELEMENTS: {
7492 num_of_elements =
7493 IterateExternalArrayElements<ExternalIntArray, int32_t>(
7494 receiver, true, false, range, visitor);
7495 break;
7496 }
7497 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
7498 num_of_elements =
7499 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
7500 receiver, true, false, range, visitor);
7501 break;
7502 }
7503 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
7504 num_of_elements =
7505 IterateExternalArrayElements<ExternalFloatArray, float>(
7506 receiver, false, false, range, visitor);
7507 break;
7508 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007509 case JSObject::DICTIONARY_ELEMENTS: {
7510 Handle<NumberDictionary> dict(receiver->element_dictionary());
7511 uint32_t capacity = dict->Capacity();
7512 for (uint32_t j = 0; j < capacity; j++) {
7513 Handle<Object> k(dict->KeyAt(j));
7514 if (dict->IsKey(*k)) {
7515 ASSERT(k->IsNumber());
7516 uint32_t index = static_cast<uint32_t>(k->Number());
7517 if (index < range) {
7518 num_of_elements++;
7519 if (visitor) {
7520 visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
7521 }
7522 }
7523 }
7524 }
7525 break;
7526 }
7527 default:
7528 UNREACHABLE();
7529 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007530 }
7531
7532 return num_of_elements;
7533}
7534
7535
7536/**
7537 * A helper function that visits elements of an Array object, and elements
7538 * on its prototypes.
7539 *
7540 * Elements on prototypes are visited first, and only elements whose indices
7541 * less than Array length are visited.
7542 *
7543 * If a ArrayConcatVisitor object is given, the visitor is called with
7544 * parameters, element's index + visitor_index_offset and the element.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007545 *
7546 * The returned number of elements is an upper bound on the actual number
7547 * of elements added. If the same element occurs in more than one object
7548 * in the array's prototype chain, it will be counted more than once, but
7549 * will only occur once in the result.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007550 */
7551static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
7552 ArrayConcatVisitor* visitor) {
7553 uint32_t range = static_cast<uint32_t>(array->length()->Number());
7554 Handle<Object> obj = array;
7555
7556 static const int kEstimatedPrototypes = 3;
7557 List< Handle<JSObject> > objects(kEstimatedPrototypes);
7558
7559 // Visit prototype first. If an element on the prototype is shadowed by
7560 // the inheritor using the same index, the ArrayConcatVisitor visits
7561 // the prototype element before the shadowing element.
7562 // The visitor can simply overwrite the old value by new value using
7563 // the same index. This follows Array::concat semantics.
7564 while (!obj->IsNull()) {
7565 objects.Add(Handle<JSObject>::cast(obj));
7566 obj = Handle<Object>(obj->GetPrototype());
7567 }
7568
7569 uint32_t nof_elements = 0;
7570 for (int i = objects.length() - 1; i >= 0; i--) {
7571 Handle<JSObject> obj = objects[i];
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007572 uint32_t encountered_elements =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007573 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007574
7575 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
7576 nof_elements = JSObject::kMaxElementCount;
7577 } else {
7578 nof_elements += encountered_elements;
7579 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007580 }
7581
7582 return nof_elements;
7583}
7584
7585
7586/**
7587 * A helper function of Runtime_ArrayConcat.
7588 *
7589 * The first argument is an Array of arrays and objects. It is the
7590 * same as the arguments array of Array::concat JS function.
7591 *
7592 * If an argument is an Array object, the function visits array
7593 * elements. If an argument is not an Array object, the function
7594 * visits the object as if it is an one-element array.
7595 *
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007596 * If the result array index overflows 32-bit unsigned integer, the rounded
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007597 * non-negative number is used as new length. For example, if one
7598 * array length is 2^32 - 1, second array length is 1, the
7599 * concatenated array length is 0.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007600 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
7601 * is one more than the last array index to get a value assigned).
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007602 */
7603static uint32_t IterateArguments(Handle<JSArray> arguments,
7604 ArrayConcatVisitor* visitor) {
7605 uint32_t visited_elements = 0;
7606 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
7607
7608 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007609 Object *element;
7610 MaybeObject* maybe_element = arguments->GetElement(i);
7611 // This if() is not expected to fail, but we have the check in the
7612 // interest of hardening the runtime calls.
7613 if (maybe_element->ToObject(&element)) {
7614 Handle<Object> obj(element);
7615 if (obj->IsJSArray()) {
7616 Handle<JSArray> array = Handle<JSArray>::cast(obj);
7617 uint32_t len = static_cast<uint32_t>(array->length()->Number());
7618 uint32_t nof_elements =
7619 IterateArrayAndPrototypeElements(array, visitor);
7620 // Total elements of array and its prototype chain can be more than
7621 // the array length, but ArrayConcat can only concatenate at most
7622 // the array length number of elements. We use the length as an estimate
7623 // for the actual number of elements added.
7624 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
7625 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
7626 visited_elements = JSArray::kMaxElementCount;
7627 } else {
7628 visited_elements += added_elements;
7629 }
7630 if (visitor) visitor->increase_index_offset(len);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007631 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007632 if (visitor) {
7633 visitor->visit(0, obj);
7634 visitor->increase_index_offset(1);
7635 }
7636 if (visited_elements < JSArray::kMaxElementCount) {
7637 visited_elements++;
7638 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007639 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007640 }
7641 }
7642 return visited_elements;
7643}
7644
7645
7646/**
7647 * Array::concat implementation.
7648 * See ECMAScript 262, 15.4.4.4.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007649 * TODO(lrn): Fix non-compliance for very large concatenations and update to
7650 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007651 */
lrn@chromium.org303ada72010-10-27 09:33:13 +00007652static MaybeObject* Runtime_ArrayConcat(Arguments args) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007653 ASSERT(args.length() == 1);
7654 HandleScope handle_scope;
7655
7656 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
7657 Handle<JSArray> arguments(arg_arrays);
7658
7659 // Pass 1: estimate the number of elements of the result
7660 // (it could be more than real numbers if prototype has elements).
7661 uint32_t result_length = 0;
7662 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
7663
7664 { AssertNoAllocation nogc;
7665 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007666 Object* obj;
7667 MaybeObject* maybe_object = arguments->GetElement(i);
7668 // This if() is not expected to fail, but we have the check in the
7669 // interest of hardening the runtime calls.
7670 if (maybe_object->ToObject(&obj)) {
7671 uint32_t length_estimate;
7672 if (obj->IsJSArray()) {
7673 length_estimate =
7674 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
7675 } else {
7676 length_estimate = 1;
7677 }
7678 if (JSObject::kMaxElementCount - result_length < length_estimate) {
7679 result_length = JSObject::kMaxElementCount;
7680 break;
7681 }
7682 result_length += length_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007683 }
7684 }
7685 }
7686
7687 // Allocate an empty array, will set length and content later.
7688 Handle<JSArray> result = Factory::NewJSArray(0);
7689
7690 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
7691 // If estimated number of elements is more than half of length, a
7692 // fixed array (fast case) is more time and space-efficient than a
7693 // dictionary.
7694 bool fast_case = (estimate_nof_elements * 2) >= result_length;
7695
7696 Handle<FixedArray> storage;
7697 if (fast_case) {
7698 // The backing storage array must have non-existing elements to
7699 // preserve holes across concat operations.
7700 storage = Factory::NewFixedArrayWithHoles(result_length);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007701 Handle<Map> fast_map =
7702 Factory::GetFastElementsMap(Handle<Map>(result->map()));
7703 result->set_map(*fast_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007704 } else {
7705 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
7706 uint32_t at_least_space_for = estimate_nof_elements +
7707 (estimate_nof_elements >> 2);
7708 storage = Handle<FixedArray>::cast(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007709 Factory::NewNumberDictionary(at_least_space_for));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007710 Handle<Map> slow_map =
7711 Factory::GetSlowElementsMap(Handle<Map>(result->map()));
7712 result->set_map(*slow_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007713 }
7714
7715 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
7716
7717 ArrayConcatVisitor visitor(storage, result_length, fast_case);
7718
7719 IterateArguments(arguments, &visitor);
7720
7721 result->set_length(*len);
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007722 // Please note the storage might have changed in the visitor.
7723 result->set_elements(*visitor.storage());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007724
7725 return *result;
7726}
7727
7728
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007729// This will not allocate (flatten the string), but it may run
7730// very slowly for very deeply nested ConsStrings. For debugging use only.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007731static MaybeObject* Runtime_GlobalPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007732 NoHandleAllocation ha;
7733 ASSERT(args.length() == 1);
7734
7735 CONVERT_CHECKED(String, string, args[0]);
7736 StringInputBuffer buffer(string);
7737 while (buffer.has_more()) {
7738 uint16_t character = buffer.GetNext();
7739 PrintF("%c", character);
7740 }
7741 return string;
7742}
7743
ager@chromium.org5ec48922009-05-05 07:25:34 +00007744// Moves all own elements of an object, that are below a limit, to positions
7745// starting at zero. All undefined values are placed after non-undefined values,
7746// and are followed by non-existing element. Does not change the length
7747// property.
7748// Returns the number of non-undefined elements collected.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007749static MaybeObject* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007750 ASSERT(args.length() == 2);
7751 CONVERT_CHECKED(JSObject, object, args[0]);
7752 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
7753 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007754}
7755
7756
7757// Move contents of argument 0 (an array) to argument 1 (an array)
lrn@chromium.org303ada72010-10-27 09:33:13 +00007758static MaybeObject* Runtime_MoveArrayContents(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007759 ASSERT(args.length() == 2);
7760 CONVERT_CHECKED(JSArray, from, args[0]);
7761 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007762 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007763 MaybeObject* maybe_new_map;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007764 if (new_elements->map() == Heap::fixed_array_map() ||
7765 new_elements->map() == Heap::fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007766 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007767 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007768 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007769 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007770 Object* new_map;
7771 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007772 to->set_map(Map::cast(new_map));
7773 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007774 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00007775 Object* obj;
7776 { MaybeObject* maybe_obj = from->ResetElements();
7777 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7778 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007779 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007780 return to;
7781}
7782
7783
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007784// How many elements does this object/array have?
lrn@chromium.org303ada72010-10-27 09:33:13 +00007785static MaybeObject* Runtime_EstimateNumberOfElements(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007786 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007787 CONVERT_CHECKED(JSObject, object, args[0]);
7788 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007789 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007790 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007791 } else if (object->IsJSArray()) {
7792 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007793 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007794 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007795 }
7796}
7797
7798
lrn@chromium.org303ada72010-10-27 09:33:13 +00007799static MaybeObject* Runtime_SwapElements(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007800 HandleScope handle_scope;
7801
7802 ASSERT_EQ(3, args.length());
7803
ager@chromium.orgac091b72010-05-05 07:34:42 +00007804 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007805 Handle<Object> key1 = args.at<Object>(1);
7806 Handle<Object> key2 = args.at<Object>(2);
7807
7808 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007809 if (!key1->ToArrayIndex(&index1)
7810 || !key2->ToArrayIndex(&index2)) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00007811 return Top::ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007812 }
7813
ager@chromium.orgac091b72010-05-05 07:34:42 +00007814 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
7815 Handle<Object> tmp1 = GetElement(jsobject, index1);
7816 Handle<Object> tmp2 = GetElement(jsobject, index2);
7817
7818 SetElement(jsobject, index1, tmp2);
7819 SetElement(jsobject, index2, tmp1);
7820
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007821 return Heap::undefined_value();
7822}
7823
7824
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007825// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00007826// might have elements. Can either return keys (positive integers) or
7827// intervals (pair of a negative integer (-start-1) followed by a
7828// positive (length)) or undefined values.
7829// Intervals can span over some keys that are not in the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007830static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007831 ASSERT(args.length() == 2);
7832 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007833 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007834 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007835 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007836 // Create an array and get all the keys into it, then remove all the
7837 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00007838 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007839 int keys_length = keys->length();
7840 for (int i = 0; i < keys_length; i++) {
7841 Object* key = keys->get(i);
7842 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007843 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007844 // Zap invalid keys.
7845 keys->set_undefined(i);
7846 }
7847 }
7848 return *Factory::NewJSArrayWithElements(keys);
7849 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007850 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007851 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
7852 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007853 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007854 uint32_t actual_length =
7855 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00007856 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007857 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00007858 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007859 single_interval->set(1, *length_object);
7860 return *Factory::NewJSArrayWithElements(single_interval);
7861 }
7862}
7863
7864
7865// DefineAccessor takes an optional final argument which is the
7866// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
7867// to the way accessors are implemented, it is set for both the getter
7868// and setter on the first call to DefineAccessor and ignored on
7869// subsequent calls.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007870static MaybeObject* Runtime_DefineAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007871 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
7872 // Compute attributes.
7873 PropertyAttributes attributes = NONE;
7874 if (args.length() == 5) {
7875 CONVERT_CHECKED(Smi, attrs, args[4]);
7876 int value = attrs->value();
7877 // Only attribute bits should be set.
7878 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
7879 attributes = static_cast<PropertyAttributes>(value);
7880 }
7881
7882 CONVERT_CHECKED(JSObject, obj, args[0]);
7883 CONVERT_CHECKED(String, name, args[1]);
7884 CONVERT_CHECKED(Smi, flag, args[2]);
7885 CONVERT_CHECKED(JSFunction, fun, args[3]);
7886 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
7887}
7888
7889
lrn@chromium.org303ada72010-10-27 09:33:13 +00007890static MaybeObject* Runtime_LookupAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007891 ASSERT(args.length() == 3);
7892 CONVERT_CHECKED(JSObject, obj, args[0]);
7893 CONVERT_CHECKED(String, name, args[1]);
7894 CONVERT_CHECKED(Smi, flag, args[2]);
7895 return obj->LookupAccessor(name, flag->value() == 0);
7896}
7897
7898
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007899#ifdef ENABLE_DEBUGGER_SUPPORT
lrn@chromium.org303ada72010-10-27 09:33:13 +00007900static MaybeObject* Runtime_DebugBreak(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007901 ASSERT(args.length() == 0);
7902 return Execution::DebugBreakHelper();
7903}
7904
7905
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007906// Helper functions for wrapping and unwrapping stack frame ids.
7907static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007908 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007909 return Smi::FromInt(id >> 2);
7910}
7911
7912
7913static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
7914 return static_cast<StackFrame::Id>(wrapped->value() << 2);
7915}
7916
7917
7918// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00007919// args[0]: debug event listener function to set or null or undefined for
7920// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007921// args[1]: object supplied during callback
lrn@chromium.org303ada72010-10-27 09:33:13 +00007922static MaybeObject* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007923 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007924 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
7925 args[0]->IsUndefined() ||
7926 args[0]->IsNull());
7927 Handle<Object> callback = args.at<Object>(0);
7928 Handle<Object> data = args.at<Object>(1);
7929 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007930
7931 return Heap::undefined_value();
7932}
7933
7934
lrn@chromium.org303ada72010-10-27 09:33:13 +00007935static MaybeObject* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00007936 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007937 StackGuard::DebugBreak();
7938 return Heap::undefined_value();
7939}
7940
7941
lrn@chromium.org303ada72010-10-27 09:33:13 +00007942static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
7943 LookupResult* result,
7944 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007945 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007946 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007947 case NORMAL:
7948 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007949 if (value->IsTheHole()) {
7950 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007951 }
7952 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007953 case FIELD:
7954 value =
7955 JSObject::cast(
7956 result->holder())->FastPropertyAt(result->GetFieldIndex());
7957 if (value->IsTheHole()) {
7958 return Heap::undefined_value();
7959 }
7960 return value;
7961 case CONSTANT_FUNCTION:
7962 return result->GetConstantFunction();
7963 case CALLBACKS: {
7964 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007965 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007966 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00007967 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00007968 if (!maybe_value->ToObject(&value)) {
7969 ASSERT(maybe_value->IsException());
7970 maybe_value = Top::pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007971 Top::clear_pending_exception();
7972 if (caught_exception != NULL) {
7973 *caught_exception = true;
7974 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007975 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00007976 }
7977 return value;
7978 } else {
7979 return Heap::undefined_value();
7980 }
7981 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007982 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007983 case MAP_TRANSITION:
7984 case CONSTANT_TRANSITION:
7985 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007986 return Heap::undefined_value();
7987 default:
7988 UNREACHABLE();
7989 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007990 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007991 return Heap::undefined_value();
7992}
7993
7994
ager@chromium.org32912102009-01-16 10:38:43 +00007995// Get debugger related details for an object property.
7996// args[0]: object holding property
7997// args[1]: name of the property
7998//
7999// The array returned contains the following information:
8000// 0: Property value
8001// 1: Property details
8002// 2: Property value is exception
8003// 3: Getter function if defined
8004// 4: Setter function if defined
8005// Items 2-4 are only filled if the property has either a getter or a setter
8006// defined through __defineGetter__ and/or __defineSetter__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008007static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008008 HandleScope scope;
8009
8010 ASSERT(args.length() == 2);
8011
8012 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8013 CONVERT_ARG_CHECKED(String, name, 1);
8014
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008015 // Make sure to set the current context to the context before the debugger was
8016 // entered (if the debugger is entered). The reason for switching context here
8017 // is that for some property lookups (accessors and interceptors) callbacks
8018 // into the embedding application can occour, and the embedding application
8019 // could have the assumption that its own global context is the current
8020 // context and not some internal debugger context.
8021 SaveContext save;
8022 if (Debug::InDebugger()) {
8023 Top::set_context(*Debug::debugger_entry()->GetContext());
8024 }
8025
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008026 // Skip the global proxy as it has no properties and always delegates to the
8027 // real global object.
8028 if (obj->IsJSGlobalProxy()) {
8029 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
8030 }
8031
8032
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008033 // Check if the name is trivially convertible to an index and get the element
8034 // if so.
8035 uint32_t index;
8036 if (name->AsArrayIndex(&index)) {
8037 Handle<FixedArray> details = Factory::NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008038 Object* element_or_char;
8039 { MaybeObject* maybe_element_or_char =
8040 Runtime::GetElementOrCharAt(obj, index);
8041 if (!maybe_element_or_char->ToObject(&element_or_char)) {
8042 return maybe_element_or_char;
8043 }
8044 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008045 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008046 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
8047 return *Factory::NewJSArrayWithElements(details);
8048 }
8049
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008050 // Find the number of objects making up this.
8051 int length = LocalPrototypeChainLength(*obj);
8052
8053 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008054 Handle<JSObject> jsproto = obj;
8055 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008056 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008057 jsproto->LocalLookup(*name, &result);
8058 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008059 // LookupResult is not GC safe as it holds raw object pointers.
8060 // GC can happen later in this code so put the required fields into
8061 // local variables using handles when required for later use.
8062 PropertyType result_type = result.type();
8063 Handle<Object> result_callback_obj;
8064 if (result_type == CALLBACKS) {
8065 result_callback_obj = Handle<Object>(result.GetCallbackObject());
8066 }
8067 Smi* property_details = result.GetPropertyDetails().AsSmi();
8068 // DebugLookupResultValue can cause GC so details from LookupResult needs
8069 // to be copied to handles before this.
8070 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008071 Object* raw_value;
8072 { MaybeObject* maybe_raw_value =
8073 DebugLookupResultValue(*obj, *name, &result, &caught_exception);
8074 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
8075 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008076 Handle<Object> value(raw_value);
8077
8078 // If the callback object is a fixed array then it contains JavaScript
8079 // getter and/or setter.
8080 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
8081 result_callback_obj->IsFixedArray();
8082 Handle<FixedArray> details =
8083 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
8084 details->set(0, *value);
8085 details->set(1, property_details);
8086 if (hasJavaScriptAccessors) {
8087 details->set(2,
8088 caught_exception ? Heap::true_value()
8089 : Heap::false_value());
8090 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
8091 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
8092 }
8093
8094 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008095 }
8096 if (i < length - 1) {
8097 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
8098 }
8099 }
8100
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008101 return Heap::undefined_value();
8102}
8103
8104
lrn@chromium.org303ada72010-10-27 09:33:13 +00008105static MaybeObject* Runtime_DebugGetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008106 HandleScope scope;
8107
8108 ASSERT(args.length() == 2);
8109
8110 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8111 CONVERT_ARG_CHECKED(String, name, 1);
8112
8113 LookupResult result;
8114 obj->Lookup(*name, &result);
8115 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008116 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008117 }
8118 return Heap::undefined_value();
8119}
8120
8121
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008122// Return the property type calculated from the property details.
8123// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008124static MaybeObject* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008125 ASSERT(args.length() == 1);
8126 CONVERT_CHECKED(Smi, details, args[0]);
8127 PropertyType type = PropertyDetails(details).type();
8128 return Smi::FromInt(static_cast<int>(type));
8129}
8130
8131
8132// Return the property attribute calculated from the property details.
8133// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008134static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008135 ASSERT(args.length() == 1);
8136 CONVERT_CHECKED(Smi, details, args[0]);
8137 PropertyAttributes attributes = PropertyDetails(details).attributes();
8138 return Smi::FromInt(static_cast<int>(attributes));
8139}
8140
8141
8142// Return the property insertion index calculated from the property details.
8143// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008144static MaybeObject* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008145 ASSERT(args.length() == 1);
8146 CONVERT_CHECKED(Smi, details, args[0]);
8147 int index = PropertyDetails(details).index();
8148 return Smi::FromInt(index);
8149}
8150
8151
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008152// Return property value from named interceptor.
8153// args[0]: object
8154// args[1]: property name
lrn@chromium.org303ada72010-10-27 09:33:13 +00008155static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008156 HandleScope scope;
8157 ASSERT(args.length() == 2);
8158 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8159 RUNTIME_ASSERT(obj->HasNamedInterceptor());
8160 CONVERT_ARG_CHECKED(String, name, 1);
8161
8162 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008163 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008164}
8165
8166
8167// Return element value from indexed interceptor.
8168// args[0]: object
8169// args[1]: index
lrn@chromium.org303ada72010-10-27 09:33:13 +00008170static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
8171 Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008172 HandleScope scope;
8173 ASSERT(args.length() == 2);
8174 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8175 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
8176 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
8177
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008178 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008179}
8180
8181
lrn@chromium.org303ada72010-10-27 09:33:13 +00008182static MaybeObject* Runtime_CheckExecutionState(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008183 ASSERT(args.length() >= 1);
8184 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00008185 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008186 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008187 return Top::Throw(Heap::illegal_execution_state_symbol());
8188 }
8189
8190 return Heap::true_value();
8191}
8192
8193
lrn@chromium.org303ada72010-10-27 09:33:13 +00008194static MaybeObject* Runtime_GetFrameCount(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008195 HandleScope scope;
8196 ASSERT(args.length() == 1);
8197
8198 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008199 Object* result;
8200 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
8201 if (!maybe_result->ToObject(&result)) return maybe_result;
8202 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008203
8204 // Count all frames which are relevant to debugging stack trace.
8205 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008206 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008207 if (id == StackFrame::NO_ID) {
8208 // If there is no JavaScript stack frame count is 0.
8209 return Smi::FromInt(0);
8210 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008211 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
8212 return Smi::FromInt(n);
8213}
8214
8215
8216static const int kFrameDetailsFrameIdIndex = 0;
8217static const int kFrameDetailsReceiverIndex = 1;
8218static const int kFrameDetailsFunctionIndex = 2;
8219static const int kFrameDetailsArgumentCountIndex = 3;
8220static const int kFrameDetailsLocalCountIndex = 4;
8221static const int kFrameDetailsSourcePositionIndex = 5;
8222static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008223static const int kFrameDetailsAtReturnIndex = 7;
8224static const int kFrameDetailsDebuggerFrameIndex = 8;
8225static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008226
8227// Return an array with frame details
8228// args[0]: number: break id
8229// args[1]: number: frame index
8230//
8231// The array returned contains the following information:
8232// 0: Frame id
8233// 1: Receiver
8234// 2: Function
8235// 3: Argument count
8236// 4: Local count
8237// 5: Source position
8238// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008239// 7: Is at return
8240// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008241// Arguments name, value
8242// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008243// Return value if any
lrn@chromium.org303ada72010-10-27 09:33:13 +00008244static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008245 HandleScope scope;
8246 ASSERT(args.length() == 2);
8247
8248 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008249 Object* check;
8250 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8251 if (!maybe_check->ToObject(&check)) return maybe_check;
8252 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008253 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8254
8255 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008256 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008257 if (id == StackFrame::NO_ID) {
8258 // If there are no JavaScript stack frames return undefined.
8259 return Heap::undefined_value();
8260 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008261 int count = 0;
8262 JavaScriptFrameIterator it(id);
8263 for (; !it.done(); it.Advance()) {
8264 if (count == index) break;
8265 count++;
8266 }
8267 if (it.done()) return Heap::undefined_value();
8268
8269 // Traverse the saved contexts chain to find the active context for the
8270 // selected frame.
8271 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008272 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008273 save = save->prev();
8274 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008275 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008276
8277 // Get the frame id.
8278 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
8279
8280 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00008281 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008282
8283 // Check for constructor frame.
8284 bool constructor = it.frame()->IsConstructor();
8285
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008286 // Get scope info and read from it for local variable information.
8287 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00008288 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008289 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008290
8291 // Get the context.
8292 Handle<Context> context(Context::cast(it.frame()->context()));
8293
8294 // Get the locals names and values into a temporary array.
8295 //
8296 // TODO(1240907): Hide compiler-introduced stack variables
8297 // (e.g. .result)? For users of the debugger, they will probably be
8298 // confusing.
8299 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
8300 for (int i = 0; i < info.NumberOfLocals(); i++) {
8301 // Name of the local.
8302 locals->set(i * 2, *info.LocalName(i));
8303
8304 // Fetch the value of the local - either from the stack or from a
8305 // heap-allocated context.
8306 if (i < info.number_of_stack_slots()) {
8307 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
8308 } else {
8309 Handle<String> name = info.LocalName(i);
8310 // Traverse the context chain to the function context as all local
8311 // variables stored in the context will be on the function context.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008312 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008313 context = Handle<Context>(context->previous());
8314 }
8315 ASSERT(context->is_function_context());
8316 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00008317 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008318 }
8319 }
8320
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008321 // Check whether this frame is positioned at return.
8322 int at_return = (index == 0) ? Debug::IsBreakAtReturn(it.frame()) : false;
8323
8324 // If positioned just before return find the value to be returned and add it
8325 // to the frame information.
8326 Handle<Object> return_value = Factory::undefined_value();
8327 if (at_return) {
8328 StackFrameIterator it2;
8329 Address internal_frame_sp = NULL;
8330 while (!it2.done()) {
8331 if (it2.frame()->is_internal()) {
8332 internal_frame_sp = it2.frame()->sp();
8333 } else {
8334 if (it2.frame()->is_java_script()) {
8335 if (it2.frame()->id() == it.frame()->id()) {
8336 // The internal frame just before the JavaScript frame contains the
8337 // value to return on top. A debug break at return will create an
8338 // internal frame to store the return value (eax/rax/r0) before
8339 // entering the debug break exit frame.
8340 if (internal_frame_sp != NULL) {
8341 return_value =
8342 Handle<Object>(Memory::Object_at(internal_frame_sp));
8343 break;
8344 }
8345 }
8346 }
8347
8348 // Indicate that the previous frame was not an internal frame.
8349 internal_frame_sp = NULL;
8350 }
8351 it2.Advance();
8352 }
8353 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008354
8355 // Now advance to the arguments adapter frame (if any). It contains all
8356 // the provided parameters whereas the function frame always have the number
8357 // of arguments matching the functions parameters. The rest of the
8358 // information (except for what is collected above) is the same.
8359 it.AdvanceToArgumentsFrame();
8360
8361 // Find the number of arguments to fill. At least fill the number of
8362 // parameters for the function and fill more if more parameters are provided.
8363 int argument_count = info.number_of_parameters();
8364 if (argument_count < it.frame()->GetProvidedParametersCount()) {
8365 argument_count = it.frame()->GetProvidedParametersCount();
8366 }
8367
8368 // Calculate the size of the result.
8369 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008370 2 * (argument_count + info.NumberOfLocals()) +
8371 (at_return ? 1 : 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008372 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8373
8374 // Add the frame id.
8375 details->set(kFrameDetailsFrameIdIndex, *frame_id);
8376
8377 // Add the function (same as in function frame).
8378 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
8379
8380 // Add the arguments count.
8381 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
8382
8383 // Add the locals count
8384 details->set(kFrameDetailsLocalCountIndex,
8385 Smi::FromInt(info.NumberOfLocals()));
8386
8387 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00008388 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008389 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
8390 } else {
8391 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
8392 }
8393
8394 // Add the constructor information.
8395 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
8396
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008397 // Add the at return information.
8398 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
8399
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008400 // Add information on whether this frame is invoked in the debugger context.
8401 details->set(kFrameDetailsDebuggerFrameIndex,
8402 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
8403
8404 // Fill the dynamic part.
8405 int details_index = kFrameDetailsFirstDynamicIndex;
8406
8407 // Add arguments name and value.
8408 for (int i = 0; i < argument_count; i++) {
8409 // Name of the argument.
8410 if (i < info.number_of_parameters()) {
8411 details->set(details_index++, *info.parameter_name(i));
8412 } else {
8413 details->set(details_index++, Heap::undefined_value());
8414 }
8415
8416 // Parameter value.
8417 if (i < it.frame()->GetProvidedParametersCount()) {
8418 details->set(details_index++, it.frame()->GetParameter(i));
8419 } else {
8420 details->set(details_index++, Heap::undefined_value());
8421 }
8422 }
8423
8424 // Add locals name and value from the temporary copy from the function frame.
8425 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
8426 details->set(details_index++, locals->get(i));
8427 }
8428
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008429 // Add the value being returned.
8430 if (at_return) {
8431 details->set(details_index++, *return_value);
8432 }
8433
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008434 // Add the receiver (same as in function frame).
8435 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
8436 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
8437 Handle<Object> receiver(it.frame()->receiver());
8438 if (!receiver->IsJSObject()) {
8439 // If the receiver is NOT a JSObject we have hit an optimization
8440 // where a value object is not converted into a wrapped JS objects.
8441 // To hide this optimization from the debugger, we wrap the receiver
8442 // by creating correct wrapper object based on the calling frame's
8443 // global context.
8444 it.Advance();
8445 Handle<Context> calling_frames_global_context(
8446 Context::cast(Context::cast(it.frame()->context())->global_context()));
8447 receiver = Factory::ToObject(receiver, calling_frames_global_context);
8448 }
8449 details->set(kFrameDetailsReceiverIndex, *receiver);
8450
8451 ASSERT_EQ(details_size, details_index);
8452 return *Factory::NewJSArrayWithElements(details);
8453}
8454
8455
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008456// Copy all the context locals into an object used to materialize a scope.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008457static void CopyContextLocalsToScopeObject(
8458 Handle<SerializedScopeInfo> serialized_scope_info,
8459 ScopeInfo<>& scope_info,
8460 Handle<Context> context,
8461 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008462 // Fill all context locals to the context extension.
8463 for (int i = Context::MIN_CONTEXT_SLOTS;
8464 i < scope_info.number_of_context_slots();
8465 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00008466 int context_index = serialized_scope_info->ContextSlotIndex(
8467 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008468
8469 // Don't include the arguments shadow (.arguments) context variable.
8470 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
8471 SetProperty(scope_object,
8472 scope_info.context_slot_name(i),
8473 Handle<Object>(context->get(context_index)), NONE);
8474 }
8475 }
8476}
8477
8478
8479// Create a plain JSObject which materializes the local scope for the specified
8480// frame.
8481static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
8482 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008483 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008484 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8485 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008486
8487 // Allocate and initialize a JSObject with all the arguments, stack locals
8488 // heap locals and extension properties of the debugged function.
8489 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
8490
8491 // First fill all parameters.
8492 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
8493 SetProperty(local_scope,
8494 scope_info.parameter_name(i),
8495 Handle<Object>(frame->GetParameter(i)), NONE);
8496 }
8497
8498 // Second fill all stack locals.
8499 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
8500 SetProperty(local_scope,
8501 scope_info.stack_slot_name(i),
8502 Handle<Object>(frame->GetExpression(i)), NONE);
8503 }
8504
8505 // Third fill all context locals.
8506 Handle<Context> frame_context(Context::cast(frame->context()));
8507 Handle<Context> function_context(frame_context->fcontext());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008508 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008509 function_context, local_scope);
8510
8511 // Finally copy any properties from the function context extension. This will
8512 // be variables introduced by eval.
8513 if (function_context->closure() == *function) {
8514 if (function_context->has_extension() &&
8515 !function_context->IsGlobalContext()) {
8516 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008517 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008518 for (int i = 0; i < keys->length(); i++) {
8519 // Names of variables introduced by eval are strings.
8520 ASSERT(keys->get(i)->IsString());
8521 Handle<String> key(String::cast(keys->get(i)));
8522 SetProperty(local_scope, key, GetProperty(ext, key), NONE);
8523 }
8524 }
8525 }
8526 return local_scope;
8527}
8528
8529
8530// Create a plain JSObject which materializes the closure content for the
8531// context.
8532static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
8533 ASSERT(context->is_function_context());
8534
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008535 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008536 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8537 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008538
8539 // Allocate and initialize a JSObject with all the content of theis function
8540 // closure.
8541 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
8542
8543 // Check whether the arguments shadow object exists.
8544 int arguments_shadow_index =
ager@chromium.orgb5737492010-07-15 09:29:43 +00008545 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
8546 NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008547 if (arguments_shadow_index >= 0) {
8548 // In this case all the arguments are available in the arguments shadow
8549 // object.
8550 Handle<JSObject> arguments_shadow(
8551 JSObject::cast(context->get(arguments_shadow_index)));
8552 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008553 // We don't expect exception-throwing getters on the arguments shadow.
8554 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008555 SetProperty(closure_scope,
8556 scope_info.parameter_name(i),
lrn@chromium.org303ada72010-10-27 09:33:13 +00008557 Handle<Object>(element),
8558 NONE);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008559 }
8560 }
8561
8562 // Fill all context locals to the context extension.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008563 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
8564 context, closure_scope);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008565
8566 // Finally copy any properties from the function context extension. This will
8567 // be variables introduced by eval.
8568 if (context->has_extension()) {
8569 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008570 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008571 for (int i = 0; i < keys->length(); i++) {
8572 // Names of variables introduced by eval are strings.
8573 ASSERT(keys->get(i)->IsString());
8574 Handle<String> key(String::cast(keys->get(i)));
8575 SetProperty(closure_scope, key, GetProperty(ext, key), NONE);
8576 }
8577 }
8578
8579 return closure_scope;
8580}
8581
8582
8583// Iterate over the actual scopes visible from a stack frame. All scopes are
8584// backed by an actual context except the local scope, which is inserted
8585// "artifically" in the context chain.
8586class ScopeIterator {
8587 public:
8588 enum ScopeType {
8589 ScopeTypeGlobal = 0,
8590 ScopeTypeLocal,
8591 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00008592 ScopeTypeClosure,
8593 // Every catch block contains an implicit with block (its parameter is
8594 // a JSContextExtensionObject) that extends current scope with a variable
8595 // holding exception object. Such with blocks are treated as scopes of their
8596 // own type.
8597 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008598 };
8599
8600 explicit ScopeIterator(JavaScriptFrame* frame)
8601 : frame_(frame),
8602 function_(JSFunction::cast(frame->function())),
8603 context_(Context::cast(frame->context())),
8604 local_done_(false),
8605 at_local_(false) {
8606
8607 // Check whether the first scope is actually a local scope.
8608 if (context_->IsGlobalContext()) {
8609 // If there is a stack slot for .result then this local scope has been
8610 // created for evaluating top level code and it is not a real local scope.
8611 // Checking for the existence of .result seems fragile, but the scope info
8612 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008613 int index = function_->shared()->scope_info()->
8614 StackSlotIndex(Heap::result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008615 at_local_ = index < 0;
8616 } else if (context_->is_function_context()) {
8617 at_local_ = true;
8618 }
8619 }
8620
8621 // More scopes?
8622 bool Done() { return context_.is_null(); }
8623
8624 // Move to the next scope.
8625 void Next() {
8626 // If at a local scope mark the local scope as passed.
8627 if (at_local_) {
8628 at_local_ = false;
8629 local_done_ = true;
8630
8631 // If the current context is not associated with the local scope the
8632 // current context is the next real scope, so don't move to the next
8633 // context in this case.
8634 if (context_->closure() != *function_) {
8635 return;
8636 }
8637 }
8638
8639 // The global scope is always the last in the chain.
8640 if (context_->IsGlobalContext()) {
8641 context_ = Handle<Context>();
8642 return;
8643 }
8644
8645 // Move to the next context.
8646 if (context_->is_function_context()) {
8647 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
8648 } else {
8649 context_ = Handle<Context>(context_->previous());
8650 }
8651
8652 // If passing the local scope indicate that the current scope is now the
8653 // local scope.
8654 if (!local_done_ &&
8655 (context_->IsGlobalContext() || (context_->is_function_context()))) {
8656 at_local_ = true;
8657 }
8658 }
8659
8660 // Return the type of the current scope.
8661 int Type() {
8662 if (at_local_) {
8663 return ScopeTypeLocal;
8664 }
8665 if (context_->IsGlobalContext()) {
8666 ASSERT(context_->global()->IsGlobalObject());
8667 return ScopeTypeGlobal;
8668 }
8669 if (context_->is_function_context()) {
8670 return ScopeTypeClosure;
8671 }
8672 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00008673 // Current scope is either an explicit with statement or a with statement
8674 // implicitely generated for a catch block.
8675 // If the extension object here is a JSContextExtensionObject then
8676 // current with statement is one frome a catch block otherwise it's a
8677 // regular with statement.
8678 if (context_->extension()->IsJSContextExtensionObject()) {
8679 return ScopeTypeCatch;
8680 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008681 return ScopeTypeWith;
8682 }
8683
8684 // Return the JavaScript object with the content of the current scope.
8685 Handle<JSObject> ScopeObject() {
8686 switch (Type()) {
8687 case ScopeIterator::ScopeTypeGlobal:
8688 return Handle<JSObject>(CurrentContext()->global());
8689 break;
8690 case ScopeIterator::ScopeTypeLocal:
8691 // Materialize the content of the local scope into a JSObject.
8692 return MaterializeLocalScope(frame_);
8693 break;
8694 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00008695 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008696 // Return the with object.
8697 return Handle<JSObject>(CurrentContext()->extension());
8698 break;
8699 case ScopeIterator::ScopeTypeClosure:
8700 // Materialize the content of the closure scope into a JSObject.
8701 return MaterializeClosure(CurrentContext());
8702 break;
8703 }
8704 UNREACHABLE();
8705 return Handle<JSObject>();
8706 }
8707
8708 // Return the context for this scope. For the local context there might not
8709 // be an actual context.
8710 Handle<Context> CurrentContext() {
8711 if (at_local_ && context_->closure() != *function_) {
8712 return Handle<Context>();
8713 }
8714 return context_;
8715 }
8716
8717#ifdef DEBUG
8718 // Debug print of the content of the current scope.
8719 void DebugPrint() {
8720 switch (Type()) {
8721 case ScopeIterator::ScopeTypeGlobal:
8722 PrintF("Global:\n");
8723 CurrentContext()->Print();
8724 break;
8725
8726 case ScopeIterator::ScopeTypeLocal: {
8727 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008728 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008729 scope_info.Print();
8730 if (!CurrentContext().is_null()) {
8731 CurrentContext()->Print();
8732 if (CurrentContext()->has_extension()) {
8733 Handle<JSObject> extension =
8734 Handle<JSObject>(CurrentContext()->extension());
8735 if (extension->IsJSContextExtensionObject()) {
8736 extension->Print();
8737 }
8738 }
8739 }
8740 break;
8741 }
8742
8743 case ScopeIterator::ScopeTypeWith: {
8744 PrintF("With:\n");
8745 Handle<JSObject> extension =
8746 Handle<JSObject>(CurrentContext()->extension());
8747 extension->Print();
8748 break;
8749 }
8750
ager@chromium.orga1645e22009-09-09 19:27:10 +00008751 case ScopeIterator::ScopeTypeCatch: {
8752 PrintF("Catch:\n");
8753 Handle<JSObject> extension =
8754 Handle<JSObject>(CurrentContext()->extension());
8755 extension->Print();
8756 break;
8757 }
8758
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008759 case ScopeIterator::ScopeTypeClosure: {
8760 PrintF("Closure:\n");
8761 CurrentContext()->Print();
8762 if (CurrentContext()->has_extension()) {
8763 Handle<JSObject> extension =
8764 Handle<JSObject>(CurrentContext()->extension());
8765 if (extension->IsJSContextExtensionObject()) {
8766 extension->Print();
8767 }
8768 }
8769 break;
8770 }
8771
8772 default:
8773 UNREACHABLE();
8774 }
8775 PrintF("\n");
8776 }
8777#endif
8778
8779 private:
8780 JavaScriptFrame* frame_;
8781 Handle<JSFunction> function_;
8782 Handle<Context> context_;
8783 bool local_done_;
8784 bool at_local_;
8785
8786 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
8787};
8788
8789
lrn@chromium.org303ada72010-10-27 09:33:13 +00008790static MaybeObject* Runtime_GetScopeCount(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008791 HandleScope scope;
8792 ASSERT(args.length() == 2);
8793
8794 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008795 Object* check;
8796 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8797 if (!maybe_check->ToObject(&check)) return maybe_check;
8798 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008799 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
8800
8801 // Get the frame where the debugging is performed.
8802 StackFrame::Id id = UnwrapFrameId(wrapped_id);
8803 JavaScriptFrameIterator it(id);
8804 JavaScriptFrame* frame = it.frame();
8805
8806 // Count the visible scopes.
8807 int n = 0;
8808 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
8809 n++;
8810 }
8811
8812 return Smi::FromInt(n);
8813}
8814
8815
8816static const int kScopeDetailsTypeIndex = 0;
8817static const int kScopeDetailsObjectIndex = 1;
8818static const int kScopeDetailsSize = 2;
8819
8820// Return an array with scope details
8821// args[0]: number: break id
8822// args[1]: number: frame index
8823// args[2]: number: scope index
8824//
8825// The array returned contains the following information:
8826// 0: Scope type
8827// 1: Scope object
lrn@chromium.org303ada72010-10-27 09:33:13 +00008828static MaybeObject* Runtime_GetScopeDetails(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008829 HandleScope scope;
8830 ASSERT(args.length() == 3);
8831
8832 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008833 Object* check;
8834 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8835 if (!maybe_check->ToObject(&check)) return maybe_check;
8836 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008837 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
8838 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
8839
8840 // Get the frame where the debugging is performed.
8841 StackFrame::Id id = UnwrapFrameId(wrapped_id);
8842 JavaScriptFrameIterator frame_it(id);
8843 JavaScriptFrame* frame = frame_it.frame();
8844
8845 // Find the requested scope.
8846 int n = 0;
8847 ScopeIterator it(frame);
8848 for (; !it.Done() && n < index; it.Next()) {
8849 n++;
8850 }
8851 if (it.Done()) {
8852 return Heap::undefined_value();
8853 }
8854
8855 // Calculate the size of the result.
8856 int details_size = kScopeDetailsSize;
8857 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8858
8859 // Fill in scope details.
8860 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008861 Handle<JSObject> scope_object = it.ScopeObject();
8862 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008863
8864 return *Factory::NewJSArrayWithElements(details);
8865}
8866
8867
lrn@chromium.org303ada72010-10-27 09:33:13 +00008868static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008869 HandleScope scope;
8870 ASSERT(args.length() == 0);
8871
8872#ifdef DEBUG
8873 // Print the scopes for the top frame.
8874 StackFrameLocator locator;
8875 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
8876 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
8877 it.DebugPrint();
8878 }
8879#endif
8880 return Heap::undefined_value();
8881}
8882
8883
lrn@chromium.org303ada72010-10-27 09:33:13 +00008884static MaybeObject* Runtime_GetCFrames(Arguments args) {
8885 // See bug 906.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00008886 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008887}
8888
8889
lrn@chromium.org303ada72010-10-27 09:33:13 +00008890static MaybeObject* Runtime_GetThreadCount(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008891 HandleScope scope;
8892 ASSERT(args.length() == 1);
8893
8894 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008895 Object* result;
8896 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
8897 if (!maybe_result->ToObject(&result)) return maybe_result;
8898 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008899
8900 // Count all archived V8 threads.
8901 int n = 0;
8902 for (ThreadState* thread = ThreadState::FirstInUse();
8903 thread != NULL;
8904 thread = thread->Next()) {
8905 n++;
8906 }
8907
8908 // Total number of threads is current thread and archived threads.
8909 return Smi::FromInt(n + 1);
8910}
8911
8912
8913static const int kThreadDetailsCurrentThreadIndex = 0;
8914static const int kThreadDetailsThreadIdIndex = 1;
8915static const int kThreadDetailsSize = 2;
8916
8917// Return an array with thread details
8918// args[0]: number: break id
8919// args[1]: number: thread index
8920//
8921// The array returned contains the following information:
8922// 0: Is current thread?
8923// 1: Thread id
lrn@chromium.org303ada72010-10-27 09:33:13 +00008924static MaybeObject* Runtime_GetThreadDetails(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008925 HandleScope scope;
8926 ASSERT(args.length() == 2);
8927
8928 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008929 Object* check;
8930 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8931 if (!maybe_check->ToObject(&check)) return maybe_check;
8932 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008933 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8934
8935 // Allocate array for result.
8936 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
8937
8938 // Thread index 0 is current thread.
8939 if (index == 0) {
8940 // Fill the details.
8941 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
8942 details->set(kThreadDetailsThreadIdIndex,
8943 Smi::FromInt(ThreadManager::CurrentId()));
8944 } else {
8945 // Find the thread with the requested index.
8946 int n = 1;
8947 ThreadState* thread = ThreadState::FirstInUse();
8948 while (index != n && thread != NULL) {
8949 thread = thread->Next();
8950 n++;
8951 }
8952 if (thread == NULL) {
8953 return Heap::undefined_value();
8954 }
8955
8956 // Fill the details.
8957 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
8958 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
8959 }
8960
8961 // Convert to JS array and return.
8962 return *Factory::NewJSArrayWithElements(details);
8963}
8964
8965
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008966// Sets the disable break state
8967// args[0]: disable break state
lrn@chromium.org303ada72010-10-27 09:33:13 +00008968static MaybeObject* Runtime_SetDisableBreak(Arguments args) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008969 HandleScope scope;
8970 ASSERT(args.length() == 1);
8971 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
8972 Debug::set_disable_break(disable_break);
8973 return Heap::undefined_value();
8974}
8975
8976
lrn@chromium.org303ada72010-10-27 09:33:13 +00008977static MaybeObject* Runtime_GetBreakLocations(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008978 HandleScope scope;
8979 ASSERT(args.length() == 1);
8980
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008981 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
8982 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008983 // Find the number of break points
8984 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
8985 if (break_locations->IsUndefined()) return Heap::undefined_value();
8986 // Return array as JS array
8987 return *Factory::NewJSArrayWithElements(
8988 Handle<FixedArray>::cast(break_locations));
8989}
8990
8991
8992// Set a break point in a function
8993// args[0]: function
8994// args[1]: number: break source position (within the function source)
8995// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00008996static MaybeObject* Runtime_SetFunctionBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008997 HandleScope scope;
8998 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008999 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9000 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009001 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9002 RUNTIME_ASSERT(source_position >= 0);
9003 Handle<Object> break_point_object_arg = args.at<Object>(2);
9004
9005 // Set break point.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009006 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009007
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009008 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009009}
9010
9011
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009012Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
9013 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009014 // Iterate the heap looking for SharedFunctionInfo generated from the
9015 // script. The inner most SharedFunctionInfo containing the source position
9016 // for the requested break point is found.
9017 // NOTE: This might reqire several heap iterations. If the SharedFunctionInfo
9018 // which is found is not compiled it is compiled and the heap is iterated
9019 // again as the compilation might create inner functions from the newly
9020 // compiled function and the actual requested break point might be in one of
9021 // these functions.
9022 bool done = false;
9023 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00009024 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009025 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009026 while (!done) {
9027 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009028 for (HeapObject* obj = iterator.next();
9029 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009030 if (obj->IsSharedFunctionInfo()) {
9031 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
9032 if (shared->script() == *script) {
9033 // If the SharedFunctionInfo found has the requested script data and
9034 // contains the source position it is a candidate.
9035 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00009036 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009037 start_position = shared->start_position();
9038 }
9039 if (start_position <= position &&
9040 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00009041 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009042 // candidate this is the new candidate.
9043 if (target.is_null()) {
9044 target_start_position = start_position;
9045 target = shared;
9046 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00009047 if (target_start_position == start_position &&
9048 shared->end_position() == target->end_position()) {
9049 // If a top-level function contain only one function
9050 // declartion the source for the top-level and the function is
9051 // the same. In that case prefer the non top-level function.
9052 if (!shared->is_toplevel()) {
9053 target_start_position = start_position;
9054 target = shared;
9055 }
9056 } else if (target_start_position <= start_position &&
9057 shared->end_position() <= target->end_position()) {
9058 // This containment check includes equality as a function inside
9059 // a top-level function can share either start or end position
9060 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009061 target_start_position = start_position;
9062 target = shared;
9063 }
9064 }
9065 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009066 }
9067 }
9068 }
9069
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009070 if (target.is_null()) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009071 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009072 }
9073
9074 // If the candidate found is compiled we are done. NOTE: when lazy
9075 // compilation of inner functions is introduced some additional checking
9076 // needs to be done here to compile inner functions.
9077 done = target->is_compiled();
9078 if (!done) {
9079 // If the candidate is not compiled compile it to reveal any inner
9080 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009081 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009082 }
9083 }
9084
9085 return *target;
9086}
9087
9088
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009089// Changes the state of a break point in a script and returns source position
9090// where break point was set. NOTE: Regarding performance see the NOTE for
9091// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009092// args[0]: script to set break point in
9093// args[1]: number: break source position (within the script source)
9094// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009095static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009096 HandleScope scope;
9097 ASSERT(args.length() == 3);
9098 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
9099 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9100 RUNTIME_ASSERT(source_position >= 0);
9101 Handle<Object> break_point_object_arg = args.at<Object>(2);
9102
9103 // Get the script from the script wrapper.
9104 RUNTIME_ASSERT(wrapper->value()->IsScript());
9105 Handle<Script> script(Script::cast(wrapper->value()));
9106
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009107 Object* result = Runtime::FindSharedFunctionInfoInScript(
9108 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009109 if (!result->IsUndefined()) {
9110 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
9111 // Find position within function. The script position might be before the
9112 // source position of the first function.
9113 int position;
9114 if (shared->start_position() > source_position) {
9115 position = 0;
9116 } else {
9117 position = source_position - shared->start_position();
9118 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009119 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
9120 position += shared->start_position();
9121 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009122 }
9123 return Heap::undefined_value();
9124}
9125
9126
9127// Clear a break point
9128// args[0]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009129static MaybeObject* Runtime_ClearBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009130 HandleScope scope;
9131 ASSERT(args.length() == 1);
9132 Handle<Object> break_point_object_arg = args.at<Object>(0);
9133
9134 // Clear break point.
9135 Debug::ClearBreakPoint(break_point_object_arg);
9136
9137 return Heap::undefined_value();
9138}
9139
9140
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009141// Change the state of break on exceptions.
9142// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
9143// args[1]: Boolean indicating on/off.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009144static MaybeObject* Runtime_ChangeBreakOnException(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009145 HandleScope scope;
9146 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009147 RUNTIME_ASSERT(args[0]->IsNumber());
9148 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009149
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009150 // If the number doesn't match an enum value, the ChangeBreakOnException
9151 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009152 ExceptionBreakType type =
9153 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009154 // Update break point state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009155 Debug::ChangeBreakOnException(type, enable);
9156 return Heap::undefined_value();
9157}
9158
9159
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009160// Returns the state of break on exceptions
9161// args[0]: boolean indicating uncaught exceptions
lrn@chromium.org303ada72010-10-27 09:33:13 +00009162static MaybeObject* Runtime_IsBreakOnException(Arguments args) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009163 HandleScope scope;
9164 ASSERT(args.length() == 1);
9165 RUNTIME_ASSERT(args[0]->IsNumber());
9166
9167 ExceptionBreakType type =
9168 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
9169 bool result = Debug::IsBreakOnException(type);
9170 return Smi::FromInt(result);
9171}
9172
9173
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009174// Prepare for stepping
9175// args[0]: break id for checking execution state
9176// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +00009177// args[2]: number of times to perform the step, for step out it is the number
9178// of frames to step down.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009179static MaybeObject* Runtime_PrepareStep(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009180 HandleScope scope;
9181 ASSERT(args.length() == 3);
9182 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009183 Object* check;
9184 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9185 if (!maybe_check->ToObject(&check)) return maybe_check;
9186 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009187 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
9188 return Top::Throw(Heap::illegal_argument_symbol());
9189 }
9190
9191 // Get the step action and check validity.
9192 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
9193 if (step_action != StepIn &&
9194 step_action != StepNext &&
9195 step_action != StepOut &&
9196 step_action != StepInMin &&
9197 step_action != StepMin) {
9198 return Top::Throw(Heap::illegal_argument_symbol());
9199 }
9200
9201 // Get the number of steps.
9202 int step_count = NumberToInt32(args[2]);
9203 if (step_count < 1) {
9204 return Top::Throw(Heap::illegal_argument_symbol());
9205 }
9206
ager@chromium.orga1645e22009-09-09 19:27:10 +00009207 // Clear all current stepping setup.
9208 Debug::ClearStepping();
9209
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009210 // Prepare step.
9211 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
9212 return Heap::undefined_value();
9213}
9214
9215
9216// Clear all stepping set by PrepareStep.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009217static MaybeObject* Runtime_ClearStepping(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009218 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009219 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009220 Debug::ClearStepping();
9221 return Heap::undefined_value();
9222}
9223
9224
9225// Creates a copy of the with context chain. The copy of the context chain is
9226// is linked to the function context supplied.
9227static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
9228 Handle<Context> function_context) {
9229 // At the bottom of the chain. Return the function context to link to.
9230 if (context_chain->is_function_context()) {
9231 return function_context;
9232 }
9233
9234 // Recursively copy the with contexts.
9235 Handle<Context> previous(context_chain->previous());
9236 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009237 Handle<Context> context = CopyWithContextChain(function_context, previous);
9238 return Factory::NewWithContext(context,
9239 extension,
9240 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009241}
9242
9243
9244// Helper function to find or create the arguments object for
9245// Runtime_DebugEvaluate.
9246static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
9247 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009248 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009249 const ScopeInfo<>* sinfo,
9250 Handle<Context> function_context) {
9251 // Try to find the value of 'arguments' to pass as parameter. If it is not
9252 // found (that is the debugged function does not reference 'arguments' and
9253 // does not support eval) then create an 'arguments' object.
9254 int index;
9255 if (sinfo->number_of_stack_slots() > 0) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009256 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009257 if (index != -1) {
9258 return Handle<Object>(frame->GetExpression(index));
9259 }
9260 }
9261
9262 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009263 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009264 if (index != -1) {
9265 return Handle<Object>(function_context->get(index));
9266 }
9267 }
9268
9269 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009270 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
9271 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009272
9273 AssertNoAllocation no_gc;
9274 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009275 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009276 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009277 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009278 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009279 return arguments;
9280}
9281
9282
9283// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +00009284// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009285// extension part has all the parameters and locals of the function on the
9286// stack frame. A function which calls eval with the code to evaluate is then
9287// compiled in this context and called in this context. As this context
9288// replaces the context of the function on the stack frame a new (empty)
9289// function is created as well to be used as the closure for the context.
9290// This function and the context acts as replacements for the function on the
9291// stack frame presenting the same view of the values of parameters and
9292// local variables as if the piece of JavaScript was evaluated at the point
9293// where the function on the stack frame is currently stopped.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009294static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009295 HandleScope scope;
9296
9297 // Check the execution state and decode arguments frame and source to be
9298 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009299 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009300 Object* check_result;
9301 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9302 if (!maybe_check_result->ToObject(&check_result)) {
9303 return maybe_check_result;
9304 }
9305 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009306 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9307 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009308 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
9309
9310 // Handle the processing of break.
9311 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009312
9313 // Get the frame where the debugging is performed.
9314 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9315 JavaScriptFrameIterator it(id);
9316 JavaScriptFrame* frame = it.frame();
9317 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009318 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009319 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009320
9321 // Traverse the saved contexts chain to find the active context for the
9322 // selected frame.
9323 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009324 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009325 save = save->prev();
9326 }
9327 ASSERT(save != NULL);
9328 SaveContext savex;
9329 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009330
9331 // Create the (empty) function replacing the function on the stack frame for
9332 // the purpose of evaluating in the context created below. It is important
9333 // that this function does not describe any parameters and local variables
9334 // in the context. If it does then this will cause problems with the lookup
9335 // in Context::Lookup, where context slots for parameters and local variables
9336 // are looked at before the extension object.
9337 Handle<JSFunction> go_between =
9338 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
9339 go_between->set_context(function->context());
9340#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009341 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009342 ASSERT(go_between_sinfo.number_of_parameters() == 0);
9343 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
9344#endif
9345
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009346 // Materialize the content of the local scope into a JSObject.
9347 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009348
9349 // Allocate a new context for the debug evaluation and set the extension
9350 // object build.
9351 Handle<Context> context =
9352 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009353 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009354 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009355 Handle<Context> frame_context(Context::cast(frame->context()));
9356 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009357 context = CopyWithContextChain(frame_context, context);
9358
9359 // Wrap the evaluation statement in a new function compiled in the newly
9360 // created context. The function has one parameter which has to be called
9361 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +00009362 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009363 // function(arguments,__source__) {return eval(__source__);}
9364 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009365 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009366 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009367 Handle<String> function_source =
9368 Factory::NewStringFromAscii(Vector<const char>(source_str,
9369 source_str_length));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009370 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +00009371 Compiler::CompileEval(function_source,
9372 context,
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00009373 context->IsGlobalContext(),
ager@chromium.orgadd848f2009-08-13 12:44:13 +00009374 Compiler::DONT_VALIDATE_JSON);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009375 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009376 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009377 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009378
9379 // Invoke the result of the compilation to get the evaluation function.
9380 bool has_pending_exception;
9381 Handle<Object> receiver(frame->receiver());
9382 Handle<Object> evaluation_function =
9383 Execution::Call(compiled_function, receiver, 0, NULL,
9384 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009385 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009386
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009387 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
9388 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009389
9390 // Invoke the evaluation function and return the result.
9391 const int argc = 2;
9392 Object** argv[argc] = { arguments.location(),
9393 Handle<Object>::cast(source).location() };
9394 Handle<Object> result =
9395 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
9396 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009397 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009398
9399 // Skip the global proxy as it has no properties and always delegates to the
9400 // real global object.
9401 if (result->IsJSGlobalProxy()) {
9402 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
9403 }
9404
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009405 return *result;
9406}
9407
9408
lrn@chromium.org303ada72010-10-27 09:33:13 +00009409static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009410 HandleScope scope;
9411
9412 // Check the execution state and decode arguments frame and source to be
9413 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009414 ASSERT(args.length() == 3);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009415 Object* check_result;
9416 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9417 if (!maybe_check_result->ToObject(&check_result)) {
9418 return maybe_check_result;
9419 }
9420 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009421 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009422 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
9423
9424 // Handle the processing of break.
9425 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009426
9427 // Enter the top context from before the debugger was invoked.
9428 SaveContext save;
9429 SaveContext* top = &save;
9430 while (top != NULL && *top->context() == *Debug::debug_context()) {
9431 top = top->prev();
9432 }
9433 if (top != NULL) {
9434 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009435 }
9436
9437 // Get the global context now set to the top context from before the
9438 // debugger was invoked.
9439 Handle<Context> context = Top::global_context();
9440
9441 // Compile the source to be evaluated.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009442 Handle<SharedFunctionInfo> shared =
9443 Compiler::CompileEval(source,
9444 context,
9445 true,
9446 Compiler::DONT_VALIDATE_JSON);
9447 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009448 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009449 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
9450 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009451
9452 // Invoke the result of the compilation to get the evaluation function.
9453 bool has_pending_exception;
9454 Handle<Object> receiver = Top::global();
9455 Handle<Object> result =
9456 Execution::Call(compiled_function, receiver, 0, NULL,
9457 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009458 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009459 return *result;
9460}
9461
9462
lrn@chromium.org303ada72010-10-27 09:33:13 +00009463static MaybeObject* Runtime_DebugGetLoadedScripts(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009464 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009465 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009466
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009467 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009468 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009469
9470 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009471 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00009472 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
9473 // Get the script wrapper in a local handle before calling GetScriptWrapper,
9474 // because using
9475 // instances->set(i, *GetScriptWrapper(script))
9476 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
9477 // already have deferenced the instances handle.
9478 Handle<JSValue> wrapper = GetScriptWrapper(script);
9479 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009480 }
9481
9482 // Return result as a JS array.
9483 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
9484 Handle<JSArray>::cast(result)->SetContent(*instances);
9485 return *result;
9486}
9487
9488
9489// Helper function used by Runtime_DebugReferencedBy below.
9490static int DebugReferencedBy(JSObject* target,
9491 Object* instance_filter, int max_references,
9492 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009493 JSFunction* arguments_function) {
9494 NoHandleAllocation ha;
9495 AssertNoAllocation no_alloc;
9496
9497 // Iterate the heap.
9498 int count = 0;
9499 JSObject* last = NULL;
9500 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009501 HeapObject* heap_obj = NULL;
9502 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009503 (max_references == 0 || count < max_references)) {
9504 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009505 if (heap_obj->IsJSObject()) {
9506 // Skip context extension objects and argument arrays as these are
9507 // checked in the context of functions using them.
9508 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009509 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009510 obj->map()->constructor() == arguments_function) {
9511 continue;
9512 }
9513
9514 // Check if the JS object has a reference to the object looked for.
9515 if (obj->ReferencesObject(target)) {
9516 // Check instance filter if supplied. This is normally used to avoid
9517 // references from mirror objects (see Runtime_IsInPrototypeChain).
9518 if (!instance_filter->IsUndefined()) {
9519 Object* V = obj;
9520 while (true) {
9521 Object* prototype = V->GetPrototype();
9522 if (prototype->IsNull()) {
9523 break;
9524 }
9525 if (instance_filter == prototype) {
9526 obj = NULL; // Don't add this object.
9527 break;
9528 }
9529 V = prototype;
9530 }
9531 }
9532
9533 if (obj != NULL) {
9534 // Valid reference found add to instance array if supplied an update
9535 // count.
9536 if (instances != NULL && count < instances_size) {
9537 instances->set(count, obj);
9538 }
9539 last = obj;
9540 count++;
9541 }
9542 }
9543 }
9544 }
9545
9546 // Check for circular reference only. This can happen when the object is only
9547 // referenced from mirrors and has a circular reference in which case the
9548 // object is not really alive and would have been garbage collected if not
9549 // referenced from the mirror.
9550 if (count == 1 && last == target) {
9551 count = 0;
9552 }
9553
9554 // Return the number of referencing objects found.
9555 return count;
9556}
9557
9558
9559// Scan the heap for objects with direct references to an object
9560// args[0]: the object to find references to
9561// args[1]: constructor function for instances to exclude (Mirror)
9562// args[2]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +00009563static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009564 ASSERT(args.length() == 3);
9565
9566 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009567 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009568
9569 // Check parameters.
9570 CONVERT_CHECKED(JSObject, target, args[0]);
9571 Object* instance_filter = args[1];
9572 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
9573 instance_filter->IsJSObject());
9574 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
9575 RUNTIME_ASSERT(max_references >= 0);
9576
9577 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009578 JSObject* arguments_boilerplate =
9579 Top::context()->global_context()->arguments_boilerplate();
9580 JSFunction* arguments_function =
9581 JSFunction::cast(arguments_boilerplate->map()->constructor());
9582
9583 // Get the number of referencing objects.
9584 int count;
9585 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00009586 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009587
9588 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009589 Object* object;
9590 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
9591 if (!maybe_object->ToObject(&object)) return maybe_object;
9592 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009593 FixedArray* instances = FixedArray::cast(object);
9594
9595 // Fill the referencing objects.
9596 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00009597 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009598
9599 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009600 Object* result;
9601 { MaybeObject* maybe_result = Heap::AllocateJSObject(
9602 Top::context()->global_context()->array_function());
9603 if (!maybe_result->ToObject(&result)) return maybe_result;
9604 }
9605 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009606 return result;
9607}
9608
9609
9610// Helper function used by Runtime_DebugConstructedBy below.
9611static int DebugConstructedBy(JSFunction* constructor, int max_references,
9612 FixedArray* instances, int instances_size) {
9613 AssertNoAllocation no_alloc;
9614
9615 // Iterate the heap.
9616 int count = 0;
9617 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009618 HeapObject* heap_obj = NULL;
9619 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009620 (max_references == 0 || count < max_references)) {
9621 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009622 if (heap_obj->IsJSObject()) {
9623 JSObject* obj = JSObject::cast(heap_obj);
9624 if (obj->map()->constructor() == constructor) {
9625 // Valid reference found add to instance array if supplied an update
9626 // count.
9627 if (instances != NULL && count < instances_size) {
9628 instances->set(count, obj);
9629 }
9630 count++;
9631 }
9632 }
9633 }
9634
9635 // Return the number of referencing objects found.
9636 return count;
9637}
9638
9639
9640// Scan the heap for objects constructed by a specific function.
9641// args[0]: the constructor to find instances of
9642// args[1]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +00009643static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009644 ASSERT(args.length() == 2);
9645
9646 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009647 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009648
9649 // Check parameters.
9650 CONVERT_CHECKED(JSFunction, constructor, args[0]);
9651 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
9652 RUNTIME_ASSERT(max_references >= 0);
9653
9654 // Get the number of referencing objects.
9655 int count;
9656 count = DebugConstructedBy(constructor, max_references, NULL, 0);
9657
9658 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009659 Object* object;
9660 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
9661 if (!maybe_object->ToObject(&object)) return maybe_object;
9662 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009663 FixedArray* instances = FixedArray::cast(object);
9664
9665 // Fill the referencing objects.
9666 count = DebugConstructedBy(constructor, max_references, instances, count);
9667
9668 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009669 Object* result;
9670 { MaybeObject* maybe_result = Heap::AllocateJSObject(
9671 Top::context()->global_context()->array_function());
9672 if (!maybe_result->ToObject(&result)) return maybe_result;
9673 }
9674 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009675 return result;
9676}
9677
9678
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009679// Find the effective prototype object as returned by __proto__.
9680// args[0]: the object to find the prototype for.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009681static MaybeObject* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009682 ASSERT(args.length() == 1);
9683
9684 CONVERT_CHECKED(JSObject, obj, args[0]);
9685
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009686 // Use the __proto__ accessor.
9687 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009688}
9689
9690
lrn@chromium.org303ada72010-10-27 09:33:13 +00009691static MaybeObject* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00009692 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009693 CPU::DebugBreak();
9694 return Heap::undefined_value();
9695}
9696
9697
lrn@chromium.org303ada72010-10-27 09:33:13 +00009698static MaybeObject* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009699#ifdef DEBUG
9700 HandleScope scope;
9701 ASSERT(args.length() == 1);
9702 // Get the function and make sure it is compiled.
9703 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009704 Handle<SharedFunctionInfo> shared(func->shared());
9705 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009706 return Failure::Exception();
9707 }
9708 func->code()->PrintLn();
9709#endif // DEBUG
9710 return Heap::undefined_value();
9711}
ager@chromium.org9085a012009-05-11 19:22:57 +00009712
9713
lrn@chromium.org303ada72010-10-27 09:33:13 +00009714static MaybeObject* Runtime_DebugDisassembleConstructor(Arguments args) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009715#ifdef DEBUG
9716 HandleScope scope;
9717 ASSERT(args.length() == 1);
9718 // Get the function and make sure it is compiled.
9719 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009720 Handle<SharedFunctionInfo> shared(func->shared());
9721 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009722 return Failure::Exception();
9723 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009724 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009725#endif // DEBUG
9726 return Heap::undefined_value();
9727}
9728
9729
lrn@chromium.org303ada72010-10-27 09:33:13 +00009730static MaybeObject* Runtime_FunctionGetInferredName(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +00009731 NoHandleAllocation ha;
9732 ASSERT(args.length() == 1);
9733
9734 CONVERT_CHECKED(JSFunction, f, args[0]);
9735 return f->shared()->inferred_name();
9736}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009737
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009738
9739static int FindSharedFunctionInfosForScript(Script* script,
9740 FixedArray* buffer) {
9741 AssertNoAllocation no_allocations;
9742
9743 int counter = 0;
9744 int buffer_size = buffer->length();
9745 HeapIterator iterator;
9746 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
9747 ASSERT(obj != NULL);
9748 if (!obj->IsSharedFunctionInfo()) {
9749 continue;
9750 }
9751 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
9752 if (shared->script() != script) {
9753 continue;
9754 }
9755 if (counter < buffer_size) {
9756 buffer->set(counter, shared);
9757 }
9758 counter++;
9759 }
9760 return counter;
9761}
9762
9763// For a script finds all SharedFunctionInfo's in the heap that points
9764// to this script. Returns JSArray of SharedFunctionInfo wrapped
9765// in OpaqueReferences.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009766static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009767 Arguments args) {
9768 ASSERT(args.length() == 1);
9769 HandleScope scope;
9770 CONVERT_CHECKED(JSValue, script_value, args[0]);
9771
9772 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
9773
9774 const int kBufferSize = 32;
9775
9776 Handle<FixedArray> array;
9777 array = Factory::NewFixedArray(kBufferSize);
9778 int number = FindSharedFunctionInfosForScript(*script, *array);
9779 if (number > kBufferSize) {
9780 array = Factory::NewFixedArray(number);
9781 FindSharedFunctionInfosForScript(*script, *array);
9782 }
9783
9784 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
9785 result->set_length(Smi::FromInt(number));
9786
9787 LiveEdit::WrapSharedFunctionInfos(result);
9788
9789 return *result;
9790}
9791
9792// For a script calculates compilation information about all its functions.
9793// The script source is explicitly specified by the second argument.
9794// The source of the actual script is not used, however it is important that
9795// all generated code keeps references to this particular instance of script.
9796// Returns a JSArray of compilation infos. The array is ordered so that
9797// each function with all its descendant is always stored in a continues range
9798// with the function itself going first. The root function is a script function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009799static MaybeObject* Runtime_LiveEditGatherCompileInfo(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009800 ASSERT(args.length() == 2);
9801 HandleScope scope;
9802 CONVERT_CHECKED(JSValue, script, args[0]);
9803 CONVERT_ARG_CHECKED(String, source, 1);
9804 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
9805
9806 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
9807
9808 if (Top::has_pending_exception()) {
9809 return Failure::Exception();
9810 }
9811
9812 return result;
9813}
9814
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009815// Changes the source of the script to a new_source.
9816// If old_script_name is provided (i.e. is a String), also creates a copy of
9817// the script with its original source and sends notification to debugger.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009818static MaybeObject* Runtime_LiveEditReplaceScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009819 ASSERT(args.length() == 3);
9820 HandleScope scope;
9821 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
9822 CONVERT_ARG_CHECKED(String, new_source, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009823 Handle<Object> old_script_name(args[2]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009824
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009825 CONVERT_CHECKED(Script, original_script_pointer,
9826 original_script_value->value());
9827 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009828
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009829 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
9830 new_source,
9831 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009832
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009833 if (old_script->IsScript()) {
9834 Handle<Script> script_handle(Script::cast(old_script));
9835 return *(GetScriptWrapper(script_handle));
9836 } else {
9837 return Heap::null_value();
9838 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009839}
9840
9841// Replaces code of SharedFunctionInfo with a new one.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009842static MaybeObject* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009843 ASSERT(args.length() == 2);
9844 HandleScope scope;
9845 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
9846 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
9847
ager@chromium.orgac091b72010-05-05 07:34:42 +00009848 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009849}
9850
9851// Connects SharedFunctionInfo to another script.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009852static MaybeObject* Runtime_LiveEditFunctionSetScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009853 ASSERT(args.length() == 2);
9854 HandleScope scope;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009855 Handle<Object> function_object(args[0]);
9856 Handle<Object> script_object(args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009857
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009858 if (function_object->IsJSValue()) {
9859 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
9860 if (script_object->IsJSValue()) {
9861 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
9862 script_object = Handle<Object>(script);
9863 }
9864
9865 LiveEdit::SetFunctionScript(function_wrapper, script_object);
9866 } else {
9867 // Just ignore this. We may not have a SharedFunctionInfo for some functions
9868 // and we check it in this function.
9869 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009870
9871 return Heap::undefined_value();
9872}
9873
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009874
9875// In a code of a parent function replaces original function as embedded object
9876// with a substitution one.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009877static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009878 ASSERT(args.length() == 3);
9879 HandleScope scope;
9880
9881 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
9882 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
9883 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
9884
9885 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
9886 subst_wrapper);
9887
9888 return Heap::undefined_value();
9889}
9890
9891
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009892// Updates positions of a shared function info (first parameter) according
9893// to script source change. Text change is described in second parameter as
9894// array of groups of 3 numbers:
9895// (change_begin, change_end, change_end_new_position).
9896// Each group describes a change in text; groups are sorted by change_begin.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009897static MaybeObject* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009898 ASSERT(args.length() == 2);
9899 HandleScope scope;
9900 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
9901 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
9902
ager@chromium.orgac091b72010-05-05 07:34:42 +00009903 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009904}
9905
9906
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009907// For array of SharedFunctionInfo's (each wrapped in JSValue)
9908// checks that none of them have activations on stacks (of any thread).
9909// Returns array of the same length with corresponding results of
9910// LiveEdit::FunctionPatchabilityStatus type.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009911static MaybeObject* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00009912 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009913 HandleScope scope;
9914 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +00009915 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009916
ager@chromium.org357bf652010-04-12 11:30:10 +00009917 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009918}
9919
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00009920// Compares 2 strings line-by-line and returns diff in form of JSArray of
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00009921// triplets (pos1, pos1_end, pos2_end) describing list of diff chunks.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009922static MaybeObject* Runtime_LiveEditCompareStringsLinewise(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00009923 ASSERT(args.length() == 2);
9924 HandleScope scope;
9925 CONVERT_ARG_CHECKED(String, s1, 0);
9926 CONVERT_ARG_CHECKED(String, s2, 1);
9927
9928 return *LiveEdit::CompareStringsLinewise(s1, s2);
9929}
9930
9931
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009932
fschneider@chromium.org086aac62010-03-17 13:18:24 +00009933// A testing entry. Returns statement position which is the closest to
9934// source_position.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009935static MaybeObject* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00009936 ASSERT(args.length() == 2);
9937 HandleScope scope;
9938 CONVERT_ARG_CHECKED(JSFunction, function, 0);
9939 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9940
9941 Handle<Code> code(function->code());
9942
9943 RelocIterator it(*code, 1 << RelocInfo::STATEMENT_POSITION);
9944 int closest_pc = 0;
9945 int distance = kMaxInt;
9946 while (!it.done()) {
9947 int statement_position = static_cast<int>(it.rinfo()->data());
9948 // Check if this break point is closer that what was previously found.
9949 if (source_position <= statement_position &&
9950 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00009951 closest_pc =
9952 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +00009953 distance = statement_position - source_position;
9954 // Check whether we can't get any closer.
9955 if (distance == 0) break;
9956 }
9957 it.next();
9958 }
9959
9960 return Smi::FromInt(closest_pc);
9961}
9962
9963
ager@chromium.org357bf652010-04-12 11:30:10 +00009964// Calls specified function with or without entering the debugger.
9965// This is used in unit tests to run code as if debugger is entered or simply
9966// to have a stack with C++ frame in the middle.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009967static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00009968 ASSERT(args.length() == 2);
9969 HandleScope scope;
9970 CONVERT_ARG_CHECKED(JSFunction, function, 0);
9971 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
9972
9973 Handle<Object> result;
9974 bool pending_exception;
9975 {
9976 if (without_debugger) {
9977 result = Execution::Call(function, Top::global(), 0, NULL,
9978 &pending_exception);
9979 } else {
9980 EnterDebugger enter_debugger;
9981 result = Execution::Call(function, Top::global(), 0, NULL,
9982 &pending_exception);
9983 }
9984 }
9985 if (!pending_exception) {
9986 return *result;
9987 } else {
9988 return Failure::Exception();
9989 }
9990}
9991
9992
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009993#endif // ENABLE_DEBUGGER_SUPPORT
9994
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009995#ifdef ENABLE_LOGGING_AND_PROFILING
9996
lrn@chromium.org303ada72010-10-27 09:33:13 +00009997static MaybeObject* Runtime_ProfilerResume(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009998 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +00009999 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010000
10001 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010002 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10003 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010004 return Heap::undefined_value();
10005}
10006
10007
lrn@chromium.org303ada72010-10-27 09:33:13 +000010008static MaybeObject* Runtime_ProfilerPause(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010009 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010010 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010011
10012 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010013 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10014 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010015 return Heap::undefined_value();
10016}
10017
10018#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010019
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010020// Finds the script object from the script data. NOTE: This operation uses
10021// heap traversal to find the function generated for the source position
10022// for the requested break point. For lazily compiled functions several heap
10023// traversals might be required rendering this operation as a rather slow
10024// operation. However for setting break points which is normally done through
10025// some kind of user interaction the performance is not crucial.
10026static Handle<Object> Runtime_GetScriptFromScriptName(
10027 Handle<String> script_name) {
10028 // Scan the heap for Script objects to find the script with the requested
10029 // script data.
10030 Handle<Script> script;
10031 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010032 HeapObject* obj = NULL;
10033 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010034 // If a script is found check if it has the script data requested.
10035 if (obj->IsScript()) {
10036 if (Script::cast(obj)->name()->IsString()) {
10037 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
10038 script = Handle<Script>(Script::cast(obj));
10039 }
10040 }
10041 }
10042 }
10043
10044 // If no script with the requested script data is found return undefined.
10045 if (script.is_null()) return Factory::undefined_value();
10046
10047 // Return the script found.
10048 return GetScriptWrapper(script);
10049}
10050
10051
10052// Get the script object from script data. NOTE: Regarding performance
10053// see the NOTE for GetScriptFromScriptData.
10054// args[0]: script data for the script to find the source for
lrn@chromium.org303ada72010-10-27 09:33:13 +000010055static MaybeObject* Runtime_GetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010056 HandleScope scope;
10057
10058 ASSERT(args.length() == 1);
10059
10060 CONVERT_CHECKED(String, script_name, args[0]);
10061
10062 // Find the requested script.
10063 Handle<Object> result =
10064 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
10065 return *result;
10066}
10067
10068
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010069// Determines whether the given stack frame should be displayed in
10070// a stack trace. The caller is the error constructor that asked
10071// for the stack trace to be collected. The first time a construct
10072// call to this function is encountered it is skipped. The seen_caller
10073// in/out parameter is used to remember if the caller has been seen
10074// yet.
10075static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
10076 bool* seen_caller) {
10077 // Only display JS frames.
10078 if (!raw_frame->is_java_script())
10079 return false;
10080 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
10081 Object* raw_fun = frame->function();
10082 // Not sure when this can happen but skip it just in case.
10083 if (!raw_fun->IsJSFunction())
10084 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010085 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010086 *seen_caller = true;
10087 return false;
10088 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010089 // Skip all frames until we've seen the caller. Also, skip the most
10090 // obvious builtin calls. Some builtin calls (such as Number.ADD
10091 // which is invoked using 'call') are very difficult to recognize
10092 // so we're leaving them in for now.
10093 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010094}
10095
10096
10097// Collect the raw data for a stack trace. Returns an array of three
10098// element segments each containing a receiver, function and native
10099// code offset.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010100static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010101 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010102 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010103 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
10104
10105 HandleScope scope;
10106
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000010107 limit = Max(limit, 0); // Ensure that limit is not negative.
10108 int initial_size = Min(limit, 10);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010109 Handle<JSArray> result = Factory::NewJSArray(initial_size * 3);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010110
10111 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010112 // If the caller parameter is a function we skip frames until we're
10113 // under it before starting to collect.
10114 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010115 int cursor = 0;
10116 int frames_seen = 0;
10117 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010118 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010119 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010120 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010121 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010122 Object* recv = frame->receiver();
10123 Object* fun = frame->function();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010124 Address pc = frame->pc();
10125 Address start = frame->code()->address();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010126 Smi* offset = Smi::FromInt(static_cast<int>(pc - start));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010127 FixedArray* elements = FixedArray::cast(result->elements());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010128 if (cursor + 2 < elements->length()) {
10129 elements->set(cursor++, recv);
10130 elements->set(cursor++, fun);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010131 elements->set(cursor++, offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010132 } else {
10133 HandleScope scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010134 Handle<Object> recv_handle(recv);
10135 Handle<Object> fun_handle(fun);
10136 SetElement(result, cursor++, recv_handle);
10137 SetElement(result, cursor++, fun_handle);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010138 SetElement(result, cursor++, Handle<Smi>(offset));
10139 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010140 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010141 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010142 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010143
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010144 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010145 return *result;
10146}
10147
10148
ager@chromium.org3811b432009-10-28 14:53:37 +000010149// Returns V8 version as a string.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010150static MaybeObject* Runtime_GetV8Version(Arguments args) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010151 ASSERT_EQ(args.length(), 0);
10152
10153 NoHandleAllocation ha;
10154
10155 const char* version_string = v8::V8::GetVersion();
10156
10157 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
10158}
10159
10160
lrn@chromium.org303ada72010-10-27 09:33:13 +000010161static MaybeObject* Runtime_Abort(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010162 ASSERT(args.length() == 2);
10163 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
10164 Smi::cast(args[1])->value());
10165 Top::PrintStack();
10166 OS::Abort();
10167 UNREACHABLE();
10168 return NULL;
10169}
10170
10171
lrn@chromium.org303ada72010-10-27 09:33:13 +000010172MUST_USE_RESULT static MaybeObject* CacheMiss(FixedArray* cache_obj,
10173 int index,
10174 Object* key_obj) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010175 ASSERT(index % 2 == 0); // index of the key
10176 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
10177 ASSERT(index < cache_obj->length());
10178
10179 HandleScope scope;
10180
10181 Handle<FixedArray> cache(cache_obj);
10182 Handle<Object> key(key_obj);
10183 Handle<JSFunction> factory(JSFunction::cast(
10184 cache->get(JSFunctionResultCache::kFactoryIndex)));
10185 // TODO(antonm): consider passing a receiver when constructing a cache.
10186 Handle<Object> receiver(Top::global_context()->global());
10187
10188 Handle<Object> value;
10189 {
10190 // This handle is nor shared, nor used later, so it's safe.
10191 Object** argv[] = { key.location() };
10192 bool pending_exception = false;
10193 value = Execution::Call(factory,
10194 receiver,
10195 1,
10196 argv,
10197 &pending_exception);
10198 if (pending_exception) return Failure::Exception();
10199 }
10200
10201 cache->set(index, *key);
10202 cache->set(index + 1, *value);
10203 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(index));
10204
10205 return *value;
10206}
10207
10208
lrn@chromium.org303ada72010-10-27 09:33:13 +000010209static MaybeObject* Runtime_GetFromCache(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010210 // This is only called from codegen, so checks might be more lax.
10211 CONVERT_CHECKED(FixedArray, cache, args[0]);
10212 Object* key = args[1];
10213
10214 const int finger_index =
10215 Smi::cast(cache->get(JSFunctionResultCache::kFingerIndex))->value();
10216
10217 Object* o = cache->get(finger_index);
10218 if (o == key) {
10219 // The fastest case: hit the same place again.
10220 return cache->get(finger_index + 1);
10221 }
10222
10223 for (int i = finger_index - 2;
10224 i >= JSFunctionResultCache::kEntriesIndex;
10225 i -= 2) {
10226 o = cache->get(i);
10227 if (o == key) {
10228 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i));
10229 return cache->get(i + 1);
10230 }
10231 }
10232
10233 const int size =
10234 Smi::cast(cache->get(JSFunctionResultCache::kCacheSizeIndex))->value();
10235 ASSERT(size <= cache->length());
10236
10237 for (int i = size - 2; i > finger_index; i -= 2) {
10238 o = cache->get(i);
10239 if (o == key) {
10240 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i));
10241 return cache->get(i + 1);
10242 }
10243 }
10244
10245 // Cache miss. If we have spare room, put new data into it, otherwise
10246 // evict post finger entry which must be least recently used.
10247 if (size < cache->length()) {
10248 cache->set(JSFunctionResultCache::kCacheSizeIndex, Smi::FromInt(size + 2));
10249 return CacheMiss(cache, size, key);
10250 } else {
antonm@chromium.org397e23c2010-04-21 12:00:05 +000010251 int target_index = finger_index + JSFunctionResultCache::kEntrySize;
10252 if (target_index == cache->length()) {
10253 target_index = JSFunctionResultCache::kEntriesIndex;
10254 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010255 return CacheMiss(cache, target_index, key);
10256 }
10257}
10258
kasper.lund44510672008-07-25 07:37:58 +000010259#ifdef DEBUG
10260// ListNatives is ONLY used by the fuzz-natives.js in debug mode
10261// Exclude the code in release mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010262static MaybeObject* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010263 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010264 HandleScope scope;
10265 Handle<JSArray> result = Factory::NewJSArray(0);
10266 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010267 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010268#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010269 { \
10270 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010271 Handle<String> name; \
10272 /* Inline runtime functions have an underscore in front of the name. */ \
10273 if (inline_runtime_functions) { \
10274 name = Factory::NewStringFromAscii( \
10275 Vector<const char>("_" #Name, StrLength("_" #Name))); \
10276 } else { \
10277 name = Factory::NewStringFromAscii( \
10278 Vector<const char>(#Name, StrLength(#Name))); \
10279 } \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010280 Handle<JSArray> pair = Factory::NewJSArray(0); \
10281 SetElement(pair, 0, name); \
10282 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
10283 SetElement(result, index++, pair); \
10284 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010285 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010286 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010287 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010288 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010289 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010290#undef ADD_ENTRY
10291 return *result;
10292}
kasper.lund44510672008-07-25 07:37:58 +000010293#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010294
10295
lrn@chromium.org303ada72010-10-27 09:33:13 +000010296static MaybeObject* Runtime_Log(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010297 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010298 CONVERT_CHECKED(String, format, args[0]);
10299 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010300 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010301 Logger::LogRuntime(chars, elms);
10302 return Heap::undefined_value();
10303}
10304
10305
lrn@chromium.org303ada72010-10-27 09:33:13 +000010306static MaybeObject* Runtime_IS_VAR(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010307 UNREACHABLE(); // implemented as macro in the parser
10308 return NULL;
10309}
10310
10311
10312// ----------------------------------------------------------------------------
10313// Implementation of Runtime
10314
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010315#define F(name, number_of_args, result_size) \
10316 { Runtime::k##name, Runtime::RUNTIME, #name, \
10317 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010318
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010319
10320#define I(name, number_of_args, result_size) \
10321 { Runtime::kInline##name, Runtime::INLINE, \
10322 "_" #name, NULL, number_of_args, result_size },
10323
10324Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010325 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010326 INLINE_FUNCTION_LIST(I)
10327 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010328};
10329
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010330
lrn@chromium.org303ada72010-10-27 09:33:13 +000010331MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010332 ASSERT(dictionary != NULL);
10333 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
10334 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010335 Object* name_symbol;
10336 { MaybeObject* maybe_name_symbol =
10337 Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
10338 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
10339 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010340 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010341 { MaybeObject* maybe_dictionary = string_dictionary->Add(
10342 String::cast(name_symbol),
10343 Smi::FromInt(i),
10344 PropertyDetails(NONE, NORMAL));
10345 if (!maybe_dictionary->ToObject(&dictionary)) {
10346 // Non-recoverable failure. Calling code must restart heap
10347 // initialization.
10348 return maybe_dictionary;
10349 }
10350 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010351 }
10352 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010353}
10354
10355
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010356Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
10357 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
10358 if (entry != kNotFound) {
10359 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
10360 int function_index = Smi::cast(smi_index)->value();
10361 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010362 }
10363 return NULL;
10364}
10365
10366
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010367Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
10368 return &(kIntrinsicFunctions[static_cast<int>(id)]);
10369}
10370
10371
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010372void Runtime::PerformGC(Object* result) {
10373 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010374 if (failure->IsRetryAfterGC()) {
10375 // Try to do a garbage collection; ignore it if it fails. The C
10376 // entry stub will throw an out-of-memory exception in that case.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000010377 Heap::CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010378 } else {
10379 // Handle last resort GC and make sure to allow future allocations
10380 // to grow the heap without causing GCs (if possible).
10381 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010382 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010383 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010384}
10385
10386
10387} } // namespace v8::internal