blob: b8133ae15e43e3fe08a65114cb60b4c0d8d5300d [file] [log] [blame]
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001// Copyright 2010 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "compiler.h"
38#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000039#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "execution.h"
43#include "jsregexp.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000044#include "liveedit.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000045#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "platform.h"
47#include "runtime.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000048#include "runtime-profiler.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000050#include "smart-pointer.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000051#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000052#include "v8threads.h"
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000053#include "string-search.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054
kasperl@chromium.org71affb52009-05-26 05:44:31 +000055namespace v8 {
56namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057
58
ager@chromium.org3e875802009-06-29 08:26:34 +000059#define RUNTIME_ASSERT(value) \
60 if (!(value)) return Top::ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
62// Cast the given object to a value of the specified type and store
63// it in a variable with the given name. If the object is not of the
64// expected type call IllegalOperation and return.
65#define CONVERT_CHECKED(Type, name, obj) \
66 RUNTIME_ASSERT(obj->Is##Type()); \
67 Type* name = Type::cast(obj);
68
69#define CONVERT_ARG_CHECKED(Type, name, index) \
70 RUNTIME_ASSERT(args[index]->Is##Type()); \
71 Handle<Type> name = args.at<Type>(index);
72
kasper.lundbd3ec4e2008-07-09 11:06:54 +000073// Cast the given object to a boolean and store it in a variable with
74// the given name. If the object is not a boolean call IllegalOperation
75// and return.
76#define CONVERT_BOOLEAN_CHECKED(name, obj) \
77 RUNTIME_ASSERT(obj->IsBoolean()); \
78 bool name = (obj)->IsTrue();
79
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000080// Cast the given object to a Smi and store its value in an int variable
81// with the given name. If the object is not a Smi call IllegalOperation
82// and return.
83#define CONVERT_SMI_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsSmi()); \
85 int name = Smi::cast(obj)->value();
86
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000087// Cast the given object to a double and store it in a variable with
88// the given name. If the object is not a number (as opposed to
89// the number not-a-number) call IllegalOperation and return.
90#define CONVERT_DOUBLE_CHECKED(name, obj) \
91 RUNTIME_ASSERT(obj->IsNumber()); \
92 double name = (obj)->Number();
93
94// Call the specified converter on the object *comand store the result in
95// a variable of the specified type with the given name. If the
96// object is not a Number call IllegalOperation and return.
97#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
98 RUNTIME_ASSERT(obj->IsNumber()); \
99 type name = NumberTo##Type(obj);
100
101// Non-reentrant string buffer for efficient general use in this file.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000102static StaticResource<StringInputBuffer> runtime_string_input_buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103
104
lrn@chromium.org303ada72010-10-27 09:33:13 +0000105MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(JSObject* boilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000106 StackLimitCheck check;
107 if (check.HasOverflowed()) return Top::StackOverflow();
108
lrn@chromium.org303ada72010-10-27 09:33:13 +0000109 Object* result;
110 { MaybeObject* maybe_result = Heap::CopyJSObject(boilerplate);
111 if (!maybe_result->ToObject(&result)) return maybe_result;
112 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000113 JSObject* copy = JSObject::cast(result);
114
115 // Deep copy local properties.
116 if (copy->HasFastProperties()) {
117 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000118 for (int i = 0; i < properties->length(); i++) {
119 Object* value = properties->get(i);
120 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000121 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000122 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
123 if (!maybe_result->ToObject(&result)) return maybe_result;
124 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000125 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000126 }
127 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000128 int nof = copy->map()->inobject_properties();
129 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000130 Object* value = copy->InObjectPropertyAt(i);
131 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000132 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000133 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
134 if (!maybe_result->ToObject(&result)) return maybe_result;
135 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000136 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000137 }
138 }
139 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000140 { MaybeObject* maybe_result =
141 Heap::AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
142 if (!maybe_result->ToObject(&result)) return maybe_result;
143 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000144 FixedArray* names = FixedArray::cast(result);
145 copy->GetLocalPropertyNames(names, 0);
146 for (int i = 0; i < names->length(); i++) {
147 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000148 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000149 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000150 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000151 // Only deep copy fields from the object literal expression.
152 // In particular, don't try to copy the length attribute of
153 // an array.
154 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000155 Object* value =
156 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000157 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000158 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
160 if (!maybe_result->ToObject(&result)) return maybe_result;
161 }
162 { MaybeObject* maybe_result =
163 copy->SetProperty(key_string, result, NONE);
164 if (!maybe_result->ToObject(&result)) return maybe_result;
165 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000166 }
167 }
168 }
169
170 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000171 // Pixel elements cannot be created using an object literal.
ager@chromium.org3811b432009-10-28 14:53:37 +0000172 ASSERT(!copy->HasPixelElements() && !copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000173 switch (copy->GetElementsKind()) {
174 case JSObject::FAST_ELEMENTS: {
175 FixedArray* elements = FixedArray::cast(copy->elements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000176 if (elements->map() == Heap::fixed_cow_array_map()) {
177 Counters::cow_arrays_created_runtime.Increment();
178#ifdef DEBUG
179 for (int i = 0; i < elements->length(); i++) {
180 ASSERT(!elements->get(i)->IsJSObject());
181 }
182#endif
183 } else {
184 for (int i = 0; i < elements->length(); i++) {
185 Object* value = elements->get(i);
186 if (value->IsJSObject()) {
187 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000188 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
189 if (!maybe_result->ToObject(&result)) return maybe_result;
190 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000191 elements->set(i, result);
192 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000193 }
194 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000195 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000196 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000197 case JSObject::DICTIONARY_ELEMENTS: {
198 NumberDictionary* element_dictionary = copy->element_dictionary();
199 int capacity = element_dictionary->Capacity();
200 for (int i = 0; i < capacity; i++) {
201 Object* k = element_dictionary->KeyAt(i);
202 if (element_dictionary->IsKey(k)) {
203 Object* value = element_dictionary->ValueAt(i);
204 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000205 JSObject* js_object = JSObject::cast(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000206 { MaybeObject* maybe_result = DeepCopyBoilerplate(js_object);
207 if (!maybe_result->ToObject(&result)) return maybe_result;
208 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000209 element_dictionary->ValueAtPut(i, result);
210 }
211 }
212 }
213 break;
214 }
215 default:
216 UNREACHABLE();
217 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000218 }
219 return copy;
220}
221
222
lrn@chromium.org303ada72010-10-27 09:33:13 +0000223static MaybeObject* Runtime_CloneLiteralBoilerplate(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000224 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
225 return DeepCopyBoilerplate(boilerplate);
226}
227
228
lrn@chromium.org303ada72010-10-27 09:33:13 +0000229static MaybeObject* Runtime_CloneShallowLiteralBoilerplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000230 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000231 return Heap::CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000232}
233
234
ager@chromium.org236ad962008-09-25 09:45:57 +0000235static Handle<Map> ComputeObjectLiteralMap(
236 Handle<Context> context,
237 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000238 bool* is_result_from_cache) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000239 int properties_length = constant_properties->length();
240 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000241 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000242 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000243 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000244 for (int p = 0; p != properties_length; p += 2) {
245 Object* key = constant_properties->get(p);
246 uint32_t element_index = 0;
247 if (key->IsSymbol()) {
248 number_of_symbol_keys++;
249 } else if (key->ToArrayIndex(&element_index)) {
250 // An index key does not require space in the property backing store.
251 number_of_properties--;
252 } else {
253 // Bail out as a non-symbol non-index key makes caching impossible.
254 // ASSERT to make sure that the if condition after the loop is false.
255 ASSERT(number_of_symbol_keys != number_of_properties);
256 break;
257 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000258 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000259 // If we only have symbols and array indices among keys then we can
260 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000261 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000262 if ((number_of_symbol_keys == number_of_properties) &&
263 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000264 // Create the fixed array with the key.
265 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000266 if (number_of_symbol_keys > 0) {
267 int index = 0;
268 for (int p = 0; p < properties_length; p += 2) {
269 Object* key = constant_properties->get(p);
270 if (key->IsSymbol()) {
271 keys->set(index++, key);
272 }
273 }
274 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000275 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000276 *is_result_from_cache = true;
ager@chromium.org236ad962008-09-25 09:45:57 +0000277 return Factory::ObjectLiteralMapFromCache(context, keys);
278 }
279 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000280 *is_result_from_cache = false;
ager@chromium.org32912102009-01-16 10:38:43 +0000281 return Factory::CopyMap(
282 Handle<Map>(context->object_function()->initial_map()),
283 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000284}
285
286
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000287static Handle<Object> CreateLiteralBoilerplate(
288 Handle<FixedArray> literals,
289 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000290
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000291
292static Handle<Object> CreateObjectLiteralBoilerplate(
293 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000294 Handle<FixedArray> constant_properties,
295 bool should_have_fast_elements) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000296 // Get the global context from the literals array. This is the
297 // context in which the function was created and we use the object
298 // function from this context to create the object literal. We do
299 // not use the object function from the current global context
300 // because this might be the object function from another context
301 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000302 Handle<Context> context =
303 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
304
305 bool is_result_from_cache;
306 Handle<Map> map = ComputeObjectLiteralMap(context,
307 constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000308 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000309
ager@chromium.org236ad962008-09-25 09:45:57 +0000310 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000311
312 // Normalize the elements of the boilerplate to save space if needed.
313 if (!should_have_fast_elements) NormalizeElements(boilerplate);
314
ager@chromium.org32912102009-01-16 10:38:43 +0000315 { // Add the constant properties to the boilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000316 int length = constant_properties->length();
ager@chromium.org236ad962008-09-25 09:45:57 +0000317 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000318 length / 2,
ager@chromium.org236ad962008-09-25 09:45:57 +0000319 !is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000320 for (int index = 0; index < length; index +=2) {
321 Handle<Object> key(constant_properties->get(index+0));
322 Handle<Object> value(constant_properties->get(index+1));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000323 if (value->IsFixedArray()) {
324 // The value contains the constant_properties of a
325 // simple object literal.
326 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
327 value = CreateLiteralBoilerplate(literals, array);
328 if (value.is_null()) return value;
329 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000330 Handle<Object> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000331 uint32_t element_index = 0;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000332 if (key->IsSymbol()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000333 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
334 // Array index as string (uint32).
335 result = SetOwnElement(boilerplate, element_index, value);
336 } else {
337 Handle<String> name(String::cast(*key));
338 ASSERT(!name->AsArrayIndex(&element_index));
339 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
340 value, NONE);
341 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000342 } else if (key->ToArrayIndex(&element_index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000343 // Array index (uint32).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000344 result = SetOwnElement(boilerplate, element_index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000345 } else {
346 // Non-uint32 number.
347 ASSERT(key->IsNumber());
348 double num = key->Number();
349 char arr[100];
350 Vector<char> buffer(arr, ARRAY_SIZE(arr));
351 const char* str = DoubleToCString(num, buffer);
352 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000353 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
354 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000356 // If setting the property on the boilerplate throws an
357 // exception, the exception is converted to an empty handle in
358 // the handle based operations. In that case, we need to
359 // convert back to an exception.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000360 if (result.is_null()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361 }
362 }
363
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000364 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000365}
366
367
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000368static Handle<Object> CreateArrayLiteralBoilerplate(
369 Handle<FixedArray> literals,
370 Handle<FixedArray> elements) {
371 // Create the JSArray.
372 Handle<JSFunction> constructor(
373 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
374 Handle<Object> object = Factory::NewJSObject(constructor);
375
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000376 const bool is_cow = (elements->map() == Heap::fixed_cow_array_map());
377 Handle<FixedArray> copied_elements =
378 is_cow ? elements : Factory::CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000379
380 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000381 if (is_cow) {
382#ifdef DEBUG
383 // Copy-on-write arrays must be shallow (and simple).
384 for (int i = 0; i < content->length(); i++) {
385 ASSERT(!content->get(i)->IsFixedArray());
386 }
387#endif
388 } else {
389 for (int i = 0; i < content->length(); i++) {
390 if (content->get(i)->IsFixedArray()) {
391 // The value contains the constant_properties of a
392 // simple object literal.
393 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
394 Handle<Object> result =
395 CreateLiteralBoilerplate(literals, fa);
396 if (result.is_null()) return result;
397 content->set(i, *result);
398 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000399 }
400 }
401
402 // Set the elements.
403 Handle<JSArray>::cast(object)->SetContent(*content);
404 return object;
405}
406
407
408static Handle<Object> CreateLiteralBoilerplate(
409 Handle<FixedArray> literals,
410 Handle<FixedArray> array) {
411 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
412 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000413 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
414 return CreateObjectLiteralBoilerplate(literals, elements, true);
415 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
416 return CreateObjectLiteralBoilerplate(literals, elements, false);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000417 case CompileTimeValue::ARRAY_LITERAL:
418 return CreateArrayLiteralBoilerplate(literals, elements);
419 default:
420 UNREACHABLE();
421 return Handle<Object>::null();
422 }
423}
424
425
lrn@chromium.org303ada72010-10-27 09:33:13 +0000426static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000427 // Takes a FixedArray of elements containing the literal elements of
428 // the array literal and produces JSArray with those elements.
429 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000430 // which contains the context from which to get the Array function
431 // to use for creating the array literal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000432 HandleScope scope;
433 ASSERT(args.length() == 3);
434 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
435 CONVERT_SMI_CHECKED(literals_index, args[1]);
436 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000437
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000438 Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements);
439 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000440
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000441 // Update the functions literal and return the boilerplate.
442 literals->set(literals_index, *object);
443 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000444}
445
446
lrn@chromium.org303ada72010-10-27 09:33:13 +0000447static MaybeObject* Runtime_CreateObjectLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000448 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000449 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000450 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
451 CONVERT_SMI_CHECKED(literals_index, args[1]);
452 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000453 CONVERT_SMI_CHECKED(fast_elements, args[3]);
454 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000455
456 // Check if boilerplate exists. If not, create it first.
457 Handle<Object> boilerplate(literals->get(literals_index));
458 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000459 boilerplate = CreateObjectLiteralBoilerplate(literals,
460 constant_properties,
461 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000462 if (boilerplate.is_null()) return Failure::Exception();
463 // Update the functions literal and return the boilerplate.
464 literals->set(literals_index, *boilerplate);
465 }
466 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
467}
468
469
lrn@chromium.org303ada72010-10-27 09:33:13 +0000470static MaybeObject* Runtime_CreateObjectLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000471 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000472 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000473 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
474 CONVERT_SMI_CHECKED(literals_index, args[1]);
475 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000476 CONVERT_SMI_CHECKED(fast_elements, args[3]);
477 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000478
479 // Check if boilerplate exists. If not, create it first.
480 Handle<Object> boilerplate(literals->get(literals_index));
481 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000482 boilerplate = CreateObjectLiteralBoilerplate(literals,
483 constant_properties,
484 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000485 if (boilerplate.is_null()) return Failure::Exception();
486 // Update the functions literal and return the boilerplate.
487 literals->set(literals_index, *boilerplate);
488 }
489 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
490}
491
492
lrn@chromium.org303ada72010-10-27 09:33:13 +0000493static MaybeObject* Runtime_CreateArrayLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000494 HandleScope scope;
495 ASSERT(args.length() == 3);
496 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
497 CONVERT_SMI_CHECKED(literals_index, args[1]);
498 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
499
500 // Check if boilerplate exists. If not, create it first.
501 Handle<Object> boilerplate(literals->get(literals_index));
502 if (*boilerplate == Heap::undefined_value()) {
503 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
504 if (boilerplate.is_null()) return Failure::Exception();
505 // Update the functions literal and return the boilerplate.
506 literals->set(literals_index, *boilerplate);
507 }
508 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
509}
510
511
lrn@chromium.org303ada72010-10-27 09:33:13 +0000512static MaybeObject* Runtime_CreateArrayLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000513 HandleScope scope;
514 ASSERT(args.length() == 3);
515 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
516 CONVERT_SMI_CHECKED(literals_index, args[1]);
517 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
518
519 // Check if boilerplate exists. If not, create it first.
520 Handle<Object> boilerplate(literals->get(literals_index));
521 if (*boilerplate == Heap::undefined_value()) {
522 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
523 if (boilerplate.is_null()) return Failure::Exception();
524 // Update the functions literal and return the boilerplate.
525 literals->set(literals_index, *boilerplate);
526 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000527 if (JSObject::cast(*boilerplate)->elements()->map() ==
528 Heap::fixed_cow_array_map()) {
529 Counters::cow_arrays_created_runtime.Increment();
530 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000531 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
532}
533
534
lrn@chromium.org303ada72010-10-27 09:33:13 +0000535static MaybeObject* Runtime_CreateCatchExtensionObject(Arguments args) {
ager@chromium.org32912102009-01-16 10:38:43 +0000536 ASSERT(args.length() == 2);
537 CONVERT_CHECKED(String, key, args[0]);
538 Object* value = args[1];
539 // Create a catch context extension object.
540 JSFunction* constructor =
541 Top::context()->global_context()->context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000542 Object* object;
543 { MaybeObject* maybe_object = Heap::AllocateJSObject(constructor);
544 if (!maybe_object->ToObject(&object)) return maybe_object;
545 }
ager@chromium.org32912102009-01-16 10:38:43 +0000546 // Assign the exception value to the catch variable and make sure
547 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000548 { MaybeObject* maybe_value =
549 JSObject::cast(object)->SetProperty(key, value, DONT_DELETE);
550 if (!maybe_value->ToObject(&value)) return maybe_value;
551 }
ager@chromium.org32912102009-01-16 10:38:43 +0000552 return object;
553}
554
555
lrn@chromium.org303ada72010-10-27 09:33:13 +0000556static MaybeObject* Runtime_ClassOf(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000557 NoHandleAllocation ha;
558 ASSERT(args.length() == 1);
559 Object* obj = args[0];
560 if (!obj->IsJSObject()) return Heap::null_value();
561 return JSObject::cast(obj)->class_name();
562}
563
ager@chromium.org7c537e22008-10-16 08:43:32 +0000564
lrn@chromium.org303ada72010-10-27 09:33:13 +0000565static MaybeObject* Runtime_IsInPrototypeChain(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000566 NoHandleAllocation ha;
567 ASSERT(args.length() == 2);
568 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
569 Object* O = args[0];
570 Object* V = args[1];
571 while (true) {
572 Object* prototype = V->GetPrototype();
573 if (prototype->IsNull()) return Heap::false_value();
574 if (O == prototype) return Heap::true_value();
575 V = prototype;
576 }
577}
578
579
ager@chromium.org9085a012009-05-11 19:22:57 +0000580// Inserts an object as the hidden prototype of another object.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000581static MaybeObject* Runtime_SetHiddenPrototype(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000582 NoHandleAllocation ha;
583 ASSERT(args.length() == 2);
584 CONVERT_CHECKED(JSObject, jsobject, args[0]);
585 CONVERT_CHECKED(JSObject, proto, args[1]);
586
587 // Sanity checks. The old prototype (that we are replacing) could
588 // theoretically be null, but if it is not null then check that we
589 // didn't already install a hidden prototype here.
590 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
591 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
592 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
593
594 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000595 Object* map_or_failure;
596 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
597 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
598 return maybe_map_or_failure;
599 }
600 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000601 Map* new_proto_map = Map::cast(map_or_failure);
602
lrn@chromium.org303ada72010-10-27 09:33:13 +0000603 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
604 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
605 return maybe_map_or_failure;
606 }
607 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000608 Map* new_map = Map::cast(map_or_failure);
609
610 // Set proto's prototype to be the old prototype of the object.
611 new_proto_map->set_prototype(jsobject->GetPrototype());
612 proto->set_map(new_proto_map);
613 new_proto_map->set_is_hidden_prototype();
614
615 // Set the object's prototype to proto.
616 new_map->set_prototype(proto);
617 jsobject->set_map(new_map);
618
619 return Heap::undefined_value();
620}
621
622
lrn@chromium.org303ada72010-10-27 09:33:13 +0000623static MaybeObject* Runtime_IsConstructCall(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000624 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000625 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000626 JavaScriptFrameIterator it;
627 return Heap::ToBoolean(it.frame()->IsConstructor());
628}
629
630
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000631// Recursively traverses hidden prototypes if property is not found
632static void GetOwnPropertyImplementation(JSObject* obj,
633 String* name,
634 LookupResult* result) {
635 obj->LocalLookupRealNamedProperty(name, result);
636
637 if (!result->IsProperty()) {
638 Object* proto = obj->GetPrototype();
639 if (proto->IsJSObject() &&
640 JSObject::cast(proto)->map()->is_hidden_prototype())
641 GetOwnPropertyImplementation(JSObject::cast(proto),
642 name, result);
643 }
644}
645
646
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000647// Enumerator used as indices into the array returned from GetOwnProperty
648enum PropertyDescriptorIndices {
649 IS_ACCESSOR_INDEX,
650 VALUE_INDEX,
651 GETTER_INDEX,
652 SETTER_INDEX,
653 WRITABLE_INDEX,
654 ENUMERABLE_INDEX,
655 CONFIGURABLE_INDEX,
656 DESCRIPTOR_SIZE
657};
658
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000659// Returns an array with the property description:
660// if args[1] is not a property on args[0]
661// returns undefined
662// if args[1] is a data property on args[0]
663// [false, value, Writeable, Enumerable, Configurable]
664// if args[1] is an accessor on args[0]
665// [true, GetFunction, SetFunction, Enumerable, Configurable]
lrn@chromium.org303ada72010-10-27 09:33:13 +0000666static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000667 ASSERT(args.length() == 2);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000668 HandleScope scope;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000669 Handle<FixedArray> elms = Factory::NewFixedArray(DESCRIPTOR_SIZE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000670 Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms);
671 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000672 CONVERT_ARG_CHECKED(JSObject, obj, 0);
673 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000674
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000675 // This could be an element.
676 uint32_t index;
677 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000678 switch (obj->HasLocalElement(index)) {
679 case JSObject::UNDEFINED_ELEMENT:
680 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000681
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000682 case JSObject::STRING_CHARACTER_ELEMENT: {
683 // Special handling of string objects according to ECMAScript 5
684 // 15.5.5.2. Note that this might be a string object with elements
685 // other than the actual string value. This is covered by the
686 // subsequent cases.
687 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
688 Handle<String> str(String::cast(js_value->value()));
689 Handle<String> substr = SubString(str, index, index+1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000690
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000691 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
692 elms->set(VALUE_INDEX, *substr);
693 elms->set(WRITABLE_INDEX, Heap::false_value());
694 elms->set(ENUMERABLE_INDEX, Heap::false_value());
695 elms->set(CONFIGURABLE_INDEX, Heap::false_value());
696 return *desc;
697 }
698
699 case JSObject::INTERCEPTED_ELEMENT:
700 case JSObject::FAST_ELEMENT: {
701 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
702 Handle<Object> element = GetElement(Handle<Object>(obj), index);
703 elms->set(VALUE_INDEX, *element);
704 elms->set(WRITABLE_INDEX, Heap::true_value());
705 elms->set(ENUMERABLE_INDEX, Heap::true_value());
706 elms->set(CONFIGURABLE_INDEX, Heap::true_value());
707 return *desc;
708 }
709
710 case JSObject::DICTIONARY_ELEMENT: {
711 NumberDictionary* dictionary = obj->element_dictionary();
712 int entry = dictionary->FindEntry(index);
713 ASSERT(entry != NumberDictionary::kNotFound);
714 PropertyDetails details = dictionary->DetailsAt(entry);
715 switch (details.type()) {
716 case CALLBACKS: {
717 // This is an accessor property with getter and/or setter.
718 FixedArray* callbacks =
719 FixedArray::cast(dictionary->ValueAt(entry));
720 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
721 elms->set(GETTER_INDEX, callbacks->get(0));
722 elms->set(SETTER_INDEX, callbacks->get(1));
723 break;
724 }
725 case NORMAL:
726 // This is a data property.
727 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
728 elms->set(VALUE_INDEX, dictionary->ValueAt(entry));
729 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
730 break;
731 default:
732 UNREACHABLE();
733 break;
734 }
735 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum()));
736 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete()));
737 return *desc;
738 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000739 }
740 }
741
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000742 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000743 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000744
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000745 if (!result.IsProperty()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000746 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000747 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000748 if (result.type() == CALLBACKS) {
749 Object* structure = result.GetCallbackObject();
ager@chromium.org5c838252010-02-19 08:53:10 +0000750 if (structure->IsProxy() || structure->IsAccessorInfo()) {
751 // Property that is internally implemented as a callback or
752 // an API defined callback.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000753 Object* value;
754 { MaybeObject* maybe_value = obj->GetPropertyWithCallback(
755 *obj, structure, *name, result.holder());
756 if (!maybe_value->ToObject(&value)) return maybe_value;
757 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000758 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
759 elms->set(VALUE_INDEX, value);
760 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000761 } else if (structure->IsFixedArray()) {
762 // __defineGetter__/__defineSetter__ callback.
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000763 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
764 elms->set(GETTER_INDEX, FixedArray::cast(structure)->get(0));
765 elms->set(SETTER_INDEX, FixedArray::cast(structure)->get(1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000766 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000767 return Heap::undefined_value();
768 }
769 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000770 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
771 elms->set(VALUE_INDEX, result.GetLazyValue());
772 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000773 }
774
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000775 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
776 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000777 return *desc;
778}
779
780
lrn@chromium.org303ada72010-10-27 09:33:13 +0000781static MaybeObject* Runtime_PreventExtensions(Arguments args) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000782 ASSERT(args.length() == 1);
783 CONVERT_CHECKED(JSObject, obj, args[0]);
784 return obj->PreventExtensions();
785}
786
lrn@chromium.org303ada72010-10-27 09:33:13 +0000787static MaybeObject* Runtime_IsExtensible(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000788 ASSERT(args.length() == 1);
789 CONVERT_CHECKED(JSObject, obj, args[0]);
790 return obj->map()->is_extensible() ? Heap::true_value()
791 : Heap::false_value();
792}
793
794
lrn@chromium.org303ada72010-10-27 09:33:13 +0000795static MaybeObject* Runtime_RegExpCompile(Arguments args) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000796 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000797 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000798 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
799 CONVERT_ARG_CHECKED(String, pattern, 1);
800 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000801 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
802 if (result.is_null()) return Failure::Exception();
803 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000804}
805
806
lrn@chromium.org303ada72010-10-27 09:33:13 +0000807static MaybeObject* Runtime_CreateApiFunction(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000808 HandleScope scope;
809 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000810 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000811 return *Factory::CreateApiFunction(data);
812}
813
814
lrn@chromium.org303ada72010-10-27 09:33:13 +0000815static MaybeObject* Runtime_IsTemplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000816 ASSERT(args.length() == 1);
817 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000818 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000819 return Heap::ToBoolean(result);
820}
821
822
lrn@chromium.org303ada72010-10-27 09:33:13 +0000823static MaybeObject* Runtime_GetTemplateField(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000824 ASSERT(args.length() == 2);
825 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000826 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000827 int index = field->value();
828 int offset = index * kPointerSize + HeapObject::kHeaderSize;
829 InstanceType type = templ->map()->instance_type();
830 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
831 type == OBJECT_TEMPLATE_INFO_TYPE);
832 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000833 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000834 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
835 } else {
836 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
837 }
838 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000839}
840
841
lrn@chromium.org303ada72010-10-27 09:33:13 +0000842static MaybeObject* Runtime_DisableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000843 ASSERT(args.length() == 1);
844 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000845 Map* old_map = object->map();
846 bool needs_access_checks = old_map->is_access_check_needed();
847 if (needs_access_checks) {
848 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000849 Object* new_map;
850 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
851 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
852 }
ager@chromium.org32912102009-01-16 10:38:43 +0000853
854 Map::cast(new_map)->set_is_access_check_needed(false);
855 object->set_map(Map::cast(new_map));
856 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000857 return needs_access_checks ? Heap::true_value() : Heap::false_value();
858}
859
860
lrn@chromium.org303ada72010-10-27 09:33:13 +0000861static MaybeObject* Runtime_EnableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000862 ASSERT(args.length() == 1);
863 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000864 Map* old_map = object->map();
865 if (!old_map->is_access_check_needed()) {
866 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000867 Object* new_map;
868 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
869 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
870 }
ager@chromium.org32912102009-01-16 10:38:43 +0000871
872 Map::cast(new_map)->set_is_access_check_needed(true);
873 object->set_map(Map::cast(new_map));
874 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000875 return Heap::undefined_value();
876}
877
878
lrn@chromium.org303ada72010-10-27 09:33:13 +0000879static Failure* ThrowRedeclarationError(const char* type, Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000880 HandleScope scope;
881 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
882 Handle<Object> args[2] = { type_handle, name };
883 Handle<Object> error =
884 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
885 return Top::Throw(*error);
886}
887
888
lrn@chromium.org303ada72010-10-27 09:33:13 +0000889static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000890 HandleScope scope;
891 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
892
ager@chromium.org3811b432009-10-28 14:53:37 +0000893 Handle<Context> context = args.at<Context>(0);
894 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000895 bool is_eval = Smi::cast(args[2])->value() == 1;
896
897 // Compute the property attributes. According to ECMA-262, section
898 // 13, page 71, the property must be read-only and
899 // non-deletable. However, neither SpiderMonkey nor KJS creates the
900 // property as read-only, so we don't either.
901 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
902
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000903 // Traverse the name/value pairs and set the properties.
904 int length = pairs->length();
905 for (int i = 0; i < length; i += 2) {
906 HandleScope scope;
907 Handle<String> name(String::cast(pairs->get(i)));
908 Handle<Object> value(pairs->get(i + 1));
909
910 // We have to declare a global const property. To capture we only
911 // assign to it when evaluating the assignment for "const x =
912 // <expr>" the initial value is the hole.
913 bool is_const_property = value->IsTheHole();
914
915 if (value->IsUndefined() || is_const_property) {
916 // Lookup the property in the global object, and don't set the
917 // value of the variable if the property is already there.
918 LookupResult lookup;
919 global->Lookup(*name, &lookup);
920 if (lookup.IsProperty()) {
921 // Determine if the property is local by comparing the holder
922 // against the global object. The information will be used to
923 // avoid throwing re-declaration errors when declaring
924 // variables or constants that exist in the prototype chain.
925 bool is_local = (*global == lookup.holder());
926 // Get the property attributes and determine if the property is
927 // read-only.
928 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
929 bool is_read_only = (attributes & READ_ONLY) != 0;
930 if (lookup.type() == INTERCEPTOR) {
931 // If the interceptor says the property is there, we
932 // just return undefined without overwriting the property.
933 // Otherwise, we continue to setting the property.
934 if (attributes != ABSENT) {
935 // Check if the existing property conflicts with regards to const.
936 if (is_local && (is_read_only || is_const_property)) {
937 const char* type = (is_read_only) ? "const" : "var";
938 return ThrowRedeclarationError(type, name);
939 };
940 // The property already exists without conflicting: Go to
941 // the next declaration.
942 continue;
943 }
944 // Fall-through and introduce the absent property by using
945 // SetProperty.
946 } else {
947 if (is_local && (is_read_only || is_const_property)) {
948 const char* type = (is_read_only) ? "const" : "var";
949 return ThrowRedeclarationError(type, name);
950 }
951 // The property already exists without conflicting: Go to
952 // the next declaration.
953 continue;
954 }
955 }
956 } else {
957 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000958 Handle<SharedFunctionInfo> shared =
959 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000960 Handle<JSFunction> function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000961 Factory::NewFunctionFromSharedFunctionInfo(shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000962 value = function;
963 }
964
965 LookupResult lookup;
966 global->LocalLookup(*name, &lookup);
967
968 PropertyAttributes attributes = is_const_property
969 ? static_cast<PropertyAttributes>(base | READ_ONLY)
970 : base;
971
972 if (lookup.IsProperty()) {
973 // There's a local property that we need to overwrite because
974 // we're either declaring a function or there's an interceptor
975 // that claims the property is absent.
976
977 // Check for conflicting re-declarations. We cannot have
978 // conflicting types in case of intercepted properties because
979 // they are absent.
980 if (lookup.type() != INTERCEPTOR &&
981 (lookup.IsReadOnly() || is_const_property)) {
982 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
983 return ThrowRedeclarationError(type, name);
984 }
985 SetProperty(global, name, value, attributes);
986 } else {
987 // If a property with this name does not already exist on the
988 // global object add the property locally. We take special
989 // precautions to always add it as a local property even in case
990 // of callbacks in the prototype chain (this rules out using
991 // SetProperty). Also, we must use the handle-based version to
992 // avoid GC issues.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000993 SetLocalPropertyIgnoreAttributes(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000994 }
995 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000996
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997 return Heap::undefined_value();
998}
999
1000
lrn@chromium.org303ada72010-10-27 09:33:13 +00001001static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001002 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001003 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001004
ager@chromium.org7c537e22008-10-16 08:43:32 +00001005 CONVERT_ARG_CHECKED(Context, context, 0);
1006 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001008 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001009 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001010 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011
1012 // Declarations are always done in the function context.
1013 context = Handle<Context>(context->fcontext());
1014
1015 int index;
1016 PropertyAttributes attributes;
1017 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001018 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001019 context->Lookup(name, flags, &index, &attributes);
1020
1021 if (attributes != ABSENT) {
1022 // The name was declared before; check for conflicting
1023 // re-declarations: This is similar to the code in parser.cc in
1024 // the AstBuildingParser::Declare function.
1025 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1026 // Functions are not read-only.
1027 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1028 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
1029 return ThrowRedeclarationError(type, name);
1030 }
1031
1032 // Initialize it if necessary.
1033 if (*initial_value != NULL) {
1034 if (index >= 0) {
1035 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001036 // the function context or the arguments object.
1037 if (holder->IsContext()) {
1038 ASSERT(holder.is_identical_to(context));
1039 if (((attributes & READ_ONLY) == 0) ||
1040 context->get(index)->IsTheHole()) {
1041 context->set(index, *initial_value);
1042 }
1043 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001044 // The holder is an arguments object.
1045 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1046 SetElement(arguments, index, initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001047 }
1048 } else {
1049 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001050 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001051 SetProperty(context_ext, name, initial_value, mode);
1052 }
1053 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001054
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001055 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001056 // The property is not in the function context. It needs to be
1057 // "declared" in the function context's extension context, or in the
1058 // global context.
1059 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001060 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001061 // The function context's extension context exists - use it.
1062 context_ext = Handle<JSObject>(context->extension());
1063 } else {
1064 // The function context's extension context does not exists - allocate
1065 // it.
1066 context_ext = Factory::NewJSObject(Top::context_extension_function());
1067 // And store it in the extension slot.
1068 context->set_extension(*context_ext);
1069 }
1070 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001071
ager@chromium.org7c537e22008-10-16 08:43:32 +00001072 // Declare the property by setting it to the initial value if provided,
1073 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1074 // constant declarations).
1075 ASSERT(!context_ext->HasLocalProperty(*name));
1076 Handle<Object> value(Heap::undefined_value());
1077 if (*initial_value != NULL) value = initial_value;
1078 SetProperty(context_ext, name, value, mode);
1079 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
1080 }
1081
1082 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001083}
1084
1085
lrn@chromium.org303ada72010-10-27 09:33:13 +00001086static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001087 NoHandleAllocation nha;
1088
1089 // Determine if we need to assign to the variable if it already
1090 // exists (based on the number of arguments).
1091 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
1092 bool assign = args.length() == 2;
1093
1094 CONVERT_ARG_CHECKED(String, name, 0);
1095 GlobalObject* global = Top::context()->global();
1096
1097 // According to ECMA-262, section 12.2, page 62, the property must
1098 // not be deletable.
1099 PropertyAttributes attributes = DONT_DELETE;
1100
1101 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001102 // there, there is a property with this name in the prototype chain.
1103 // We follow Safari and Firefox behavior and only set the property
1104 // locally if there is an explicit initialization value that we have
1105 // to assign to the property. When adding the property we take
1106 // special precautions to always add it as a local property even in
1107 // case of callbacks in the prototype chain (this rules out using
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001108 // SetProperty). We have SetLocalPropertyIgnoreAttributes for
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001109 // this.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001110 // Note that objects can have hidden prototypes, so we need to traverse
1111 // the whole chain of hidden prototypes to do a 'local' lookup.
1112 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001113 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001114 while (true) {
1115 real_holder->LocalLookup(*name, &lookup);
1116 if (lookup.IsProperty()) {
1117 // Determine if this is a redeclaration of something read-only.
1118 if (lookup.IsReadOnly()) {
1119 // If we found readonly property on one of hidden prototypes,
1120 // just shadow it.
1121 if (real_holder != Top::context()->global()) break;
1122 return ThrowRedeclarationError("const", name);
1123 }
1124
1125 // Determine if this is a redeclaration of an intercepted read-only
1126 // property and figure out if the property exists at all.
1127 bool found = true;
1128 PropertyType type = lookup.type();
1129 if (type == INTERCEPTOR) {
1130 HandleScope handle_scope;
1131 Handle<JSObject> holder(real_holder);
1132 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1133 real_holder = *holder;
1134 if (intercepted == ABSENT) {
1135 // The interceptor claims the property isn't there. We need to
1136 // make sure to introduce it.
1137 found = false;
1138 } else if ((intercepted & READ_ONLY) != 0) {
1139 // The property is present, but read-only. Since we're trying to
1140 // overwrite it with a variable declaration we must throw a
1141 // re-declaration error. However if we found readonly property
1142 // on one of hidden prototypes, just shadow it.
1143 if (real_holder != Top::context()->global()) break;
1144 return ThrowRedeclarationError("const", name);
1145 }
1146 }
1147
1148 if (found && !assign) {
1149 // The global property is there and we're not assigning any value
1150 // to it. Just return.
1151 return Heap::undefined_value();
1152 }
1153
1154 // Assign the value (or undefined) to the property.
1155 Object* value = (assign) ? args[1] : Heap::undefined_value();
1156 return real_holder->SetProperty(&lookup, *name, value, attributes);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001157 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001158
1159 Object* proto = real_holder->GetPrototype();
1160 if (!proto->IsJSObject())
1161 break;
1162
1163 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1164 break;
1165
1166 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001167 }
1168
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001169 global = Top::context()->global();
1170 if (assign) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001171 return global->SetLocalPropertyIgnoreAttributes(*name,
1172 args[1],
1173 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001174 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001175 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001176}
1177
1178
lrn@chromium.org303ada72010-10-27 09:33:13 +00001179static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001180 // All constants are declared with an initial value. The name
1181 // of the constant is the first argument and the initial value
1182 // is the second.
1183 RUNTIME_ASSERT(args.length() == 2);
1184 CONVERT_ARG_CHECKED(String, name, 0);
1185 Handle<Object> value = args.at<Object>(1);
1186
1187 // Get the current global object from top.
1188 GlobalObject* global = Top::context()->global();
1189
1190 // According to ECMA-262, section 12.2, page 62, the property must
1191 // not be deletable. Since it's a const, it must be READ_ONLY too.
1192 PropertyAttributes attributes =
1193 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1194
1195 // Lookup the property locally in the global object. If it isn't
1196 // there, we add the property and take special precautions to always
1197 // add it as a local property even in case of callbacks in the
1198 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001199 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001200 LookupResult lookup;
1201 global->LocalLookup(*name, &lookup);
1202 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001203 return global->SetLocalPropertyIgnoreAttributes(*name,
1204 *value,
1205 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001206 }
1207
1208 // Determine if this is a redeclaration of something not
1209 // read-only. In case the result is hidden behind an interceptor we
1210 // need to ask it for the property attributes.
1211 if (!lookup.IsReadOnly()) {
1212 if (lookup.type() != INTERCEPTOR) {
1213 return ThrowRedeclarationError("var", name);
1214 }
1215
1216 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1217
1218 // Throw re-declaration error if the intercepted property is present
1219 // but not read-only.
1220 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1221 return ThrowRedeclarationError("var", name);
1222 }
1223
1224 // Restore global object from context (in case of GC) and continue
1225 // with setting the value because the property is either absent or
1226 // read-only. We also have to do redo the lookup.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001227 HandleScope handle_scope;
1228 Handle<GlobalObject>global(Top::context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001229
1230 // BUG 1213579: Handle the case where we have to set a read-only
1231 // property through an interceptor and only do it if it's
1232 // uninitialized, e.g. the hole. Nirk...
lrn@chromium.org303ada72010-10-27 09:33:13 +00001233 SetProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001234 return *value;
1235 }
1236
1237 // Set the value, but only we're assigning the initial value to a
1238 // constant. For now, we determine this by checking if the
1239 // current value is the hole.
1240 PropertyType type = lookup.type();
1241 if (type == FIELD) {
1242 FixedArray* properties = global->properties();
1243 int index = lookup.GetFieldIndex();
1244 if (properties->get(index)->IsTheHole()) {
1245 properties->set(index, *value);
1246 }
1247 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001248 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1249 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001250 }
1251 } else {
1252 // Ignore re-initialization of constants that have already been
1253 // assigned a function value.
1254 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1255 }
1256
1257 // Use the set value as the result of the operation.
1258 return *value;
1259}
1260
1261
lrn@chromium.org303ada72010-10-27 09:33:13 +00001262static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001263 HandleScope scope;
1264 ASSERT(args.length() == 3);
1265
1266 Handle<Object> value(args[0]);
1267 ASSERT(!value->IsTheHole());
1268 CONVERT_ARG_CHECKED(Context, context, 1);
1269 Handle<String> name(String::cast(args[2]));
1270
1271 // Initializations are always done in the function context.
1272 context = Handle<Context>(context->fcontext());
1273
1274 int index;
1275 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001276 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001277 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278 context->Lookup(name, flags, &index, &attributes);
1279
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001280 // In most situations, the property introduced by the const
1281 // declaration should be present in the context extension object.
1282 // However, because declaration and initialization are separate, the
1283 // property might have been deleted (if it was introduced by eval)
1284 // before we reach the initialization point.
1285 //
1286 // Example:
1287 //
1288 // function f() { eval("delete x; const x;"); }
1289 //
1290 // In that case, the initialization behaves like a normal assignment
1291 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001292 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001293 // Property was found in a context.
1294 if (holder->IsContext()) {
1295 // The holder cannot be the function context. If it is, there
1296 // should have been a const redeclaration error when declaring
1297 // the const property.
1298 ASSERT(!holder.is_identical_to(context));
1299 if ((attributes & READ_ONLY) == 0) {
1300 Handle<Context>::cast(holder)->set(index, *value);
1301 }
1302 } else {
1303 // The holder is an arguments object.
1304 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001305 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1306 SetElement(arguments, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001307 }
1308 return *value;
1309 }
1310
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001311 // The property could not be found, we introduce it in the global
1312 // context.
1313 if (attributes == ABSENT) {
1314 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
1315 SetProperty(global, name, value, NONE);
1316 return *value;
1317 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001318
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001319 // The property was present in a context extension object.
1320 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001321
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001322 if (*context_ext == context->extension()) {
1323 // This is the property that was introduced by the const
1324 // declaration. Set it if it hasn't been set before. NOTE: We
1325 // cannot use GetProperty() to get the current value as it
1326 // 'unholes' the value.
1327 LookupResult lookup;
1328 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1329 ASSERT(lookup.IsProperty()); // the property was declared
1330 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1331
1332 PropertyType type = lookup.type();
1333 if (type == FIELD) {
1334 FixedArray* properties = context_ext->properties();
1335 int index = lookup.GetFieldIndex();
1336 if (properties->get(index)->IsTheHole()) {
1337 properties->set(index, *value);
1338 }
1339 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001340 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1341 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001342 }
1343 } else {
1344 // We should not reach here. Any real, named property should be
1345 // either a field or a dictionary slot.
1346 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001347 }
1348 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001349 // The property was found in a different context extension object.
1350 // Set it if it is not a read-only property.
1351 if ((attributes & READ_ONLY) == 0) {
1352 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
1353 // Setting a property might throw an exception. Exceptions
1354 // are converted to empty handles in handle operations. We
1355 // need to convert back to exceptions here.
1356 if (set.is_null()) {
1357 ASSERT(Top::has_pending_exception());
1358 return Failure::Exception();
1359 }
1360 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001361 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001362
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001363 return *value;
1364}
1365
1366
lrn@chromium.org303ada72010-10-27 09:33:13 +00001367static MaybeObject* Runtime_OptimizeObjectForAddingMultipleProperties(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001368 Arguments args) {
1369 HandleScope scope;
1370 ASSERT(args.length() == 2);
1371 CONVERT_ARG_CHECKED(JSObject, object, 0);
1372 CONVERT_SMI_CHECKED(properties, args[1]);
1373 if (object->HasFastProperties()) {
1374 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1375 }
1376 return *object;
1377}
1378
1379
lrn@chromium.org303ada72010-10-27 09:33:13 +00001380static MaybeObject* Runtime_RegExpExec(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001381 HandleScope scope;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001382 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001383 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1384 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001385 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001386 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001387 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001388 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001389 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001390 RUNTIME_ASSERT(index >= 0);
1391 RUNTIME_ASSERT(index <= subject->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001392 Counters::regexp_entry_runtime.Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001393 Handle<Object> result = RegExpImpl::Exec(regexp,
1394 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001395 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001396 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001397 if (result.is_null()) return Failure::Exception();
1398 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399}
1400
1401
lrn@chromium.org303ada72010-10-27 09:33:13 +00001402static MaybeObject* Runtime_RegExpConstructResult(Arguments args) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001403 ASSERT(args.length() == 3);
1404 CONVERT_SMI_CHECKED(elements_count, args[0]);
1405 if (elements_count > JSArray::kMaxFastElementsLength) {
1406 return Top::ThrowIllegalOperation();
1407 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001408 Object* new_object;
1409 { MaybeObject* maybe_new_object =
1410 Heap::AllocateFixedArrayWithHoles(elements_count);
1411 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1412 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001413 FixedArray* elements = FixedArray::cast(new_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001414 { MaybeObject* maybe_new_object = Heap::AllocateRaw(JSRegExpResult::kSize,
1415 NEW_SPACE,
1416 OLD_POINTER_SPACE);
1417 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1418 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001419 {
1420 AssertNoAllocation no_gc;
1421 HandleScope scope;
1422 reinterpret_cast<HeapObject*>(new_object)->
1423 set_map(Top::global_context()->regexp_result_map());
1424 }
1425 JSArray* array = JSArray::cast(new_object);
1426 array->set_properties(Heap::empty_fixed_array());
1427 array->set_elements(elements);
1428 array->set_length(Smi::FromInt(elements_count));
1429 // Write in-object properties after the length of the array.
1430 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1431 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1432 return array;
1433}
1434
1435
lrn@chromium.org303ada72010-10-27 09:33:13 +00001436static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001437 AssertNoAllocation no_alloc;
1438 ASSERT(args.length() == 5);
1439 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1440 CONVERT_CHECKED(String, source, args[1]);
1441
1442 Object* global = args[2];
1443 if (!global->IsTrue()) global = Heap::false_value();
1444
1445 Object* ignoreCase = args[3];
1446 if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value();
1447
1448 Object* multiline = args[4];
1449 if (!multiline->IsTrue()) multiline = Heap::false_value();
1450
1451 Map* map = regexp->map();
1452 Object* constructor = map->constructor();
1453 if (constructor->IsJSFunction() &&
1454 JSFunction::cast(constructor)->initial_map() == map) {
1455 // If we still have the original map, set in-object properties directly.
1456 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1457 // TODO(lrn): Consider skipping write barrier on booleans as well.
1458 // Both true and false should be in oldspace at all times.
1459 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1460 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1461 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1462 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1463 Smi::FromInt(0),
1464 SKIP_WRITE_BARRIER);
1465 return regexp;
1466 }
1467
lrn@chromium.org303ada72010-10-27 09:33:13 +00001468 // Map has changed, so use generic, but slower, method. Since these
1469 // properties were all added as DONT_DELETE they must be present and
1470 // normal so no failures can be expected.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001471 PropertyAttributes final =
1472 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1473 PropertyAttributes writable =
1474 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001475 MaybeObject* result;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001476 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::source_symbol(),
1477 source,
1478 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001479 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001480 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::global_symbol(),
1481 global,
1482 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001483 ASSERT(!result->IsFailure());
1484 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001485 regexp->SetLocalPropertyIgnoreAttributes(Heap::ignore_case_symbol(),
1486 ignoreCase,
1487 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001488 ASSERT(!result->IsFailure());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001489 result = regexp->SetLocalPropertyIgnoreAttributes(Heap::multiline_symbol(),
1490 multiline,
1491 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001492 ASSERT(!result->IsFailure());
1493 result =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001494 regexp->SetLocalPropertyIgnoreAttributes(Heap::last_index_symbol(),
1495 Smi::FromInt(0),
1496 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001497 ASSERT(!result->IsFailure());
1498 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001499 return regexp;
1500}
1501
1502
lrn@chromium.org303ada72010-10-27 09:33:13 +00001503static MaybeObject* Runtime_FinishArrayPrototypeSetup(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001504 HandleScope scope;
1505 ASSERT(args.length() == 1);
1506 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1507 // This is necessary to enable fast checks for absence of elements
1508 // on Array.prototype and below.
1509 prototype->set_elements(Heap::empty_fixed_array());
1510 return Smi::FromInt(0);
1511}
1512
1513
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001514static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
1515 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001516 Builtins::Name builtin_name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001517 Handle<String> key = Factory::LookupAsciiSymbol(name);
1518 Handle<Code> code(Builtins::builtin(builtin_name));
1519 Handle<JSFunction> optimized = Factory::NewFunction(key,
1520 JS_OBJECT_TYPE,
1521 JSObject::kHeaderSize,
1522 code,
1523 false);
1524 optimized->shared()->DontAdaptArguments();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001525 SetProperty(holder, key, optimized, NONE);
1526 return optimized;
1527}
1528
1529
lrn@chromium.org303ada72010-10-27 09:33:13 +00001530static MaybeObject* Runtime_SpecialArrayFunctions(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001531 HandleScope scope;
1532 ASSERT(args.length() == 1);
1533 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1534
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001535 InstallBuiltin(holder, "pop", Builtins::ArrayPop);
1536 InstallBuiltin(holder, "push", Builtins::ArrayPush);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001537 InstallBuiltin(holder, "shift", Builtins::ArrayShift);
1538 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
1539 InstallBuiltin(holder, "slice", Builtins::ArraySlice);
1540 InstallBuiltin(holder, "splice", Builtins::ArraySplice);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001541 InstallBuiltin(holder, "concat", Builtins::ArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001542
1543 return *holder;
1544}
1545
1546
lrn@chromium.org303ada72010-10-27 09:33:13 +00001547static MaybeObject* Runtime_GetGlobalReceiver(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001548 // Returns a real global receiver, not one of builtins object.
1549 Context* global_context = Top::context()->global()->global_context();
1550 return global_context->global()->global_receiver();
1551}
1552
1553
lrn@chromium.org303ada72010-10-27 09:33:13 +00001554static MaybeObject* Runtime_MaterializeRegExpLiteral(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001555 HandleScope scope;
1556 ASSERT(args.length() == 4);
1557 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1558 int index = Smi::cast(args[1])->value();
1559 Handle<String> pattern = args.at<String>(2);
1560 Handle<String> flags = args.at<String>(3);
1561
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001562 // Get the RegExp function from the context in the literals array.
1563 // This is the RegExp function from the context in which the
1564 // function was created. We do not use the RegExp function from the
1565 // current global context because this might be the RegExp function
1566 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001567 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001568 Handle<JSFunction>(
1569 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001570 // Compute the regular expression literal.
1571 bool has_pending_exception;
1572 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001573 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1574 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001575 if (has_pending_exception) {
1576 ASSERT(Top::has_pending_exception());
1577 return Failure::Exception();
1578 }
1579 literals->set(index, *regexp);
1580 return *regexp;
1581}
1582
1583
lrn@chromium.org303ada72010-10-27 09:33:13 +00001584static MaybeObject* Runtime_FunctionGetName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001585 NoHandleAllocation ha;
1586 ASSERT(args.length() == 1);
1587
1588 CONVERT_CHECKED(JSFunction, f, args[0]);
1589 return f->shared()->name();
1590}
1591
1592
lrn@chromium.org303ada72010-10-27 09:33:13 +00001593static MaybeObject* Runtime_FunctionSetName(Arguments args) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001594 NoHandleAllocation ha;
1595 ASSERT(args.length() == 2);
1596
1597 CONVERT_CHECKED(JSFunction, f, args[0]);
1598 CONVERT_CHECKED(String, name, args[1]);
1599 f->shared()->set_name(name);
1600 return Heap::undefined_value();
1601}
1602
1603
lrn@chromium.org303ada72010-10-27 09:33:13 +00001604static MaybeObject* Runtime_FunctionRemovePrototype(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001605 NoHandleAllocation ha;
1606 ASSERT(args.length() == 1);
1607
1608 CONVERT_CHECKED(JSFunction, f, args[0]);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001609 Object* obj;
1610 { MaybeObject* maybe_obj = f->RemovePrototype();
1611 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1612 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001613
1614 return Heap::undefined_value();
1615}
1616
1617
lrn@chromium.org303ada72010-10-27 09:33:13 +00001618static MaybeObject* Runtime_FunctionGetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001619 HandleScope scope;
1620 ASSERT(args.length() == 1);
1621
1622 CONVERT_CHECKED(JSFunction, fun, args[0]);
1623 Handle<Object> script = Handle<Object>(fun->shared()->script());
1624 if (!script->IsScript()) return Heap::undefined_value();
1625
1626 return *GetScriptWrapper(Handle<Script>::cast(script));
1627}
1628
1629
lrn@chromium.org303ada72010-10-27 09:33:13 +00001630static MaybeObject* Runtime_FunctionGetSourceCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001631 NoHandleAllocation ha;
1632 ASSERT(args.length() == 1);
1633
1634 CONVERT_CHECKED(JSFunction, f, args[0]);
1635 return f->shared()->GetSourceCode();
1636}
1637
1638
lrn@chromium.org303ada72010-10-27 09:33:13 +00001639static MaybeObject* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001640 NoHandleAllocation ha;
1641 ASSERT(args.length() == 1);
1642
1643 CONVERT_CHECKED(JSFunction, fun, args[0]);
1644 int pos = fun->shared()->start_position();
1645 return Smi::FromInt(pos);
1646}
1647
1648
lrn@chromium.org303ada72010-10-27 09:33:13 +00001649static MaybeObject* Runtime_FunctionGetPositionForOffset(Arguments args) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001650 ASSERT(args.length() == 2);
1651
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001652 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001653 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1654
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001655 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1656
1657 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001658 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001659}
1660
1661
1662
lrn@chromium.org303ada72010-10-27 09:33:13 +00001663static MaybeObject* Runtime_FunctionSetInstanceClassName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001664 NoHandleAllocation ha;
1665 ASSERT(args.length() == 2);
1666
1667 CONVERT_CHECKED(JSFunction, fun, args[0]);
1668 CONVERT_CHECKED(String, name, args[1]);
1669 fun->SetInstanceClassName(name);
1670 return Heap::undefined_value();
1671}
1672
1673
lrn@chromium.org303ada72010-10-27 09:33:13 +00001674static MaybeObject* Runtime_FunctionSetLength(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001675 NoHandleAllocation ha;
1676 ASSERT(args.length() == 2);
1677
1678 CONVERT_CHECKED(JSFunction, fun, args[0]);
1679 CONVERT_CHECKED(Smi, length, args[1]);
1680 fun->shared()->set_length(length->value());
1681 return length;
1682}
1683
1684
lrn@chromium.org303ada72010-10-27 09:33:13 +00001685static MaybeObject* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001686 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001687 ASSERT(args.length() == 2);
1688
1689 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001690 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001691 Object* obj;
1692 { MaybeObject* maybe_obj =
1693 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1694 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1695 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001696 return args[0]; // return TOS
1697}
1698
1699
lrn@chromium.org303ada72010-10-27 09:33:13 +00001700static MaybeObject* Runtime_FunctionIsAPIFunction(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001701 NoHandleAllocation ha;
1702 ASSERT(args.length() == 1);
1703
1704 CONVERT_CHECKED(JSFunction, f, args[0]);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001705 return f->shared()->IsApiFunction() ? Heap::true_value()
1706 : Heap::false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001707}
1708
lrn@chromium.org303ada72010-10-27 09:33:13 +00001709static MaybeObject* Runtime_FunctionIsBuiltin(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001710 NoHandleAllocation ha;
1711 ASSERT(args.length() == 1);
1712
1713 CONVERT_CHECKED(JSFunction, f, args[0]);
1714 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
1715}
1716
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001717
lrn@chromium.org303ada72010-10-27 09:33:13 +00001718static MaybeObject* Runtime_SetCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001719 HandleScope scope;
1720 ASSERT(args.length() == 2);
1721
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001722 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001723 Handle<Object> code = args.at<Object>(1);
1724
1725 Handle<Context> context(target->context());
1726
1727 if (!code->IsNull()) {
1728 RUNTIME_ASSERT(code->IsJSFunction());
1729 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001730 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001731
1732 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001733 return Failure::Exception();
1734 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001735 // Since we don't store the source for this we should never
1736 // optimize this.
1737 shared->code()->set_optimizable(false);
1738
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001739 // Set the code, scope info, formal parameter count,
1740 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001741 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001742 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001743 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001744 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001745 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001746 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001747 // Set the source code of the target function to undefined.
1748 // SetCode is only used for built-in constructors like String,
1749 // Array, and Object, and some web code
1750 // doesn't like seeing source code for constructors.
1751 target->shared()->set_script(Heap::undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001752 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001753 // Clear the optimization hints related to the compiled code as these are no
1754 // longer valid when the code is overwritten.
1755 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001756 context = Handle<Context>(fun->context());
1757
1758 // Make sure we get a fresh copy of the literal vector to avoid
1759 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001760 int number_of_literals = fun->NumberOfLiterals();
1761 Handle<FixedArray> literals =
1762 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001763 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001764 // Insert the object, regexp and array functions in the literals
1765 // array prefix. These are the functions that will be used when
1766 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001767 literals->set(JSFunction::kLiteralGlobalContextIndex,
1768 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001769 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001770 // It's okay to skip the write barrier here because the literals
1771 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001772 target->set_literals(*literals, SKIP_WRITE_BARRIER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001773 target->set_next_function_link(Heap::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001774 }
1775
1776 target->set_context(*context);
1777 return *target;
1778}
1779
1780
lrn@chromium.org303ada72010-10-27 09:33:13 +00001781static MaybeObject* Runtime_SetExpectedNumberOfProperties(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001782 HandleScope scope;
1783 ASSERT(args.length() == 2);
1784 CONVERT_ARG_CHECKED(JSFunction, function, 0);
1785 CONVERT_SMI_CHECKED(num, args[1]);
1786 RUNTIME_ASSERT(num >= 0);
1787 SetExpectedNofProperties(function, num);
1788 return Heap::undefined_value();
1789}
1790
1791
lrn@chromium.org303ada72010-10-27 09:33:13 +00001792MUST_USE_RESULT static MaybeObject* CharFromCode(Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001793 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001794 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001795 if (code <= 0xffff) {
1796 return Heap::LookupSingleCharacterStringFromCode(code);
1797 }
1798 }
1799 return Heap::empty_string();
1800}
1801
1802
lrn@chromium.org303ada72010-10-27 09:33:13 +00001803static MaybeObject* Runtime_StringCharCodeAt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001804 NoHandleAllocation ha;
1805 ASSERT(args.length() == 2);
1806
1807 CONVERT_CHECKED(String, subject, args[0]);
1808 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001809 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001810
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001811 uint32_t i = 0;
1812 if (index->IsSmi()) {
1813 int value = Smi::cast(index)->value();
1814 if (value < 0) return Heap::nan_value();
1815 i = value;
1816 } else {
1817 ASSERT(index->IsHeapNumber());
1818 double value = HeapNumber::cast(index)->value();
1819 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00001820 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001821
1822 // Flatten the string. If someone wants to get a char at an index
1823 // in a cons string, it is likely that more indices will be
1824 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001825 Object* flat;
1826 { MaybeObject* maybe_flat = subject->TryFlatten();
1827 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
1828 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001829 subject = String::cast(flat);
1830
1831 if (i >= static_cast<uint32_t>(subject->length())) {
1832 return Heap::nan_value();
1833 }
1834
1835 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001836}
1837
1838
lrn@chromium.org303ada72010-10-27 09:33:13 +00001839static MaybeObject* Runtime_CharFromCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001840 NoHandleAllocation ha;
1841 ASSERT(args.length() == 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001842 return CharFromCode(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001843}
1844
lrn@chromium.org25156de2010-04-06 13:10:27 +00001845
1846class FixedArrayBuilder {
1847 public:
1848 explicit FixedArrayBuilder(int initial_capacity)
1849 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
1850 length_(0) {
1851 // Require a non-zero initial size. Ensures that doubling the size to
1852 // extend the array will work.
1853 ASSERT(initial_capacity > 0);
1854 }
1855
1856 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
1857 : array_(backing_store),
1858 length_(0) {
1859 // Require a non-zero initial size. Ensures that doubling the size to
1860 // extend the array will work.
1861 ASSERT(backing_store->length() > 0);
1862 }
1863
1864 bool HasCapacity(int elements) {
1865 int length = array_->length();
1866 int required_length = length_ + elements;
1867 return (length >= required_length);
1868 }
1869
1870 void EnsureCapacity(int elements) {
1871 int length = array_->length();
1872 int required_length = length_ + elements;
1873 if (length < required_length) {
1874 int new_length = length;
1875 do {
1876 new_length *= 2;
1877 } while (new_length < required_length);
1878 Handle<FixedArray> extended_array =
1879 Factory::NewFixedArrayWithHoles(new_length);
1880 array_->CopyTo(0, *extended_array, 0, length_);
1881 array_ = extended_array;
1882 }
1883 }
1884
1885 void Add(Object* value) {
1886 ASSERT(length_ < capacity());
1887 array_->set(length_, value);
1888 length_++;
1889 }
1890
1891 void Add(Smi* value) {
1892 ASSERT(length_ < capacity());
1893 array_->set(length_, value);
1894 length_++;
1895 }
1896
1897 Handle<FixedArray> array() {
1898 return array_;
1899 }
1900
1901 int length() {
1902 return length_;
1903 }
1904
1905 int capacity() {
1906 return array_->length();
1907 }
1908
1909 Handle<JSArray> ToJSArray() {
1910 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
1911 result_array->set_length(Smi::FromInt(length_));
1912 return result_array;
1913 }
1914
1915 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
1916 target_array->set_elements(*array_);
1917 target_array->set_length(Smi::FromInt(length_));
1918 return target_array;
1919 }
1920
1921 private:
1922 Handle<FixedArray> array_;
1923 int length_;
1924};
1925
1926
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001927// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001928const int kStringBuilderConcatHelperLengthBits = 11;
1929const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001930
1931template <typename schar>
1932static inline void StringBuilderConcatHelper(String*,
1933 schar*,
1934 FixedArray*,
1935 int);
1936
lrn@chromium.org25156de2010-04-06 13:10:27 +00001937typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
1938 StringBuilderSubstringLength;
1939typedef BitField<int,
1940 kStringBuilderConcatHelperLengthBits,
1941 kStringBuilderConcatHelperPositionBits>
1942 StringBuilderSubstringPosition;
1943
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001944
1945class ReplacementStringBuilder {
1946 public:
1947 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
lrn@chromium.org25156de2010-04-06 13:10:27 +00001948 : array_builder_(estimated_part_count),
1949 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001950 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00001951 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001952 // Require a non-zero initial size. Ensures that doubling the size to
1953 // extend the array will work.
1954 ASSERT(estimated_part_count > 0);
1955 }
1956
lrn@chromium.org25156de2010-04-06 13:10:27 +00001957 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
1958 int from,
1959 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001960 ASSERT(from >= 0);
1961 int length = to - from;
1962 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001963 if (StringBuilderSubstringLength::is_valid(length) &&
1964 StringBuilderSubstringPosition::is_valid(from)) {
1965 int encoded_slice = StringBuilderSubstringLength::encode(length) |
1966 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001967 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001968 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001969 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001970 builder->Add(Smi::FromInt(-length));
1971 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001972 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00001973 }
1974
1975
1976 void EnsureCapacity(int elements) {
1977 array_builder_.EnsureCapacity(elements);
1978 }
1979
1980
1981 void AddSubjectSlice(int from, int to) {
1982 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001983 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001984 }
1985
1986
1987 void AddString(Handle<String> string) {
1988 int length = string->length();
1989 ASSERT(length > 0);
1990 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00001991 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001992 is_ascii_ = false;
1993 }
1994 IncrementCharacterCount(length);
1995 }
1996
1997
1998 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001999 if (array_builder_.length() == 0) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002000 return Factory::empty_string();
2001 }
2002
2003 Handle<String> joined_string;
2004 if (is_ascii_) {
2005 joined_string = NewRawAsciiString(character_count_);
2006 AssertNoAllocation no_alloc;
2007 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2008 char* char_buffer = seq->GetChars();
2009 StringBuilderConcatHelper(*subject_,
2010 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002011 *array_builder_.array(),
2012 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002013 } else {
2014 // Non-ASCII.
2015 joined_string = NewRawTwoByteString(character_count_);
2016 AssertNoAllocation no_alloc;
2017 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2018 uc16* char_buffer = seq->GetChars();
2019 StringBuilderConcatHelper(*subject_,
2020 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002021 *array_builder_.array(),
2022 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002023 }
2024 return joined_string;
2025 }
2026
2027
2028 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002029 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002030 V8::FatalProcessOutOfMemory("String.replace result too large.");
2031 }
2032 character_count_ += by;
2033 }
2034
lrn@chromium.org25156de2010-04-06 13:10:27 +00002035 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002036 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002037 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002038
lrn@chromium.org25156de2010-04-06 13:10:27 +00002039 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002040 Handle<String> NewRawAsciiString(int size) {
2041 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
2042 }
2043
2044
2045 Handle<String> NewRawTwoByteString(int size) {
2046 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
2047 }
2048
2049
2050 void AddElement(Object* element) {
2051 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002052 ASSERT(array_builder_.capacity() > array_builder_.length());
2053 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002054 }
2055
lrn@chromium.org25156de2010-04-06 13:10:27 +00002056 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002057 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002058 int character_count_;
2059 bool is_ascii_;
2060};
2061
2062
2063class CompiledReplacement {
2064 public:
2065 CompiledReplacement()
2066 : parts_(1), replacement_substrings_(0) {}
2067
2068 void Compile(Handle<String> replacement,
2069 int capture_count,
2070 int subject_length);
2071
2072 void Apply(ReplacementStringBuilder* builder,
2073 int match_from,
2074 int match_to,
2075 Handle<JSArray> last_match_info);
2076
2077 // Number of distinct parts of the replacement pattern.
2078 int parts() {
2079 return parts_.length();
2080 }
2081 private:
2082 enum PartType {
2083 SUBJECT_PREFIX = 1,
2084 SUBJECT_SUFFIX,
2085 SUBJECT_CAPTURE,
2086 REPLACEMENT_SUBSTRING,
2087 REPLACEMENT_STRING,
2088
2089 NUMBER_OF_PART_TYPES
2090 };
2091
2092 struct ReplacementPart {
2093 static inline ReplacementPart SubjectMatch() {
2094 return ReplacementPart(SUBJECT_CAPTURE, 0);
2095 }
2096 static inline ReplacementPart SubjectCapture(int capture_index) {
2097 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2098 }
2099 static inline ReplacementPart SubjectPrefix() {
2100 return ReplacementPart(SUBJECT_PREFIX, 0);
2101 }
2102 static inline ReplacementPart SubjectSuffix(int subject_length) {
2103 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2104 }
2105 static inline ReplacementPart ReplacementString() {
2106 return ReplacementPart(REPLACEMENT_STRING, 0);
2107 }
2108 static inline ReplacementPart ReplacementSubString(int from, int to) {
2109 ASSERT(from >= 0);
2110 ASSERT(to > from);
2111 return ReplacementPart(-from, to);
2112 }
2113
2114 // If tag <= 0 then it is the negation of a start index of a substring of
2115 // the replacement pattern, otherwise it's a value from PartType.
2116 ReplacementPart(int tag, int data)
2117 : tag(tag), data(data) {
2118 // Must be non-positive or a PartType value.
2119 ASSERT(tag < NUMBER_OF_PART_TYPES);
2120 }
2121 // Either a value of PartType or a non-positive number that is
2122 // the negation of an index into the replacement string.
2123 int tag;
2124 // The data value's interpretation depends on the value of tag:
2125 // tag == SUBJECT_PREFIX ||
2126 // tag == SUBJECT_SUFFIX: data is unused.
2127 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2128 // tag == REPLACEMENT_SUBSTRING ||
2129 // tag == REPLACEMENT_STRING: data is index into array of substrings
2130 // of the replacement string.
2131 // tag <= 0: Temporary representation of the substring of the replacement
2132 // string ranging over -tag .. data.
2133 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2134 // substring objects.
2135 int data;
2136 };
2137
2138 template<typename Char>
2139 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2140 Vector<Char> characters,
2141 int capture_count,
2142 int subject_length) {
2143 int length = characters.length();
2144 int last = 0;
2145 for (int i = 0; i < length; i++) {
2146 Char c = characters[i];
2147 if (c == '$') {
2148 int next_index = i + 1;
2149 if (next_index == length) { // No next character!
2150 break;
2151 }
2152 Char c2 = characters[next_index];
2153 switch (c2) {
2154 case '$':
2155 if (i > last) {
2156 // There is a substring before. Include the first "$".
2157 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2158 last = next_index + 1; // Continue after the second "$".
2159 } else {
2160 // Let the next substring start with the second "$".
2161 last = next_index;
2162 }
2163 i = next_index;
2164 break;
2165 case '`':
2166 if (i > last) {
2167 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2168 }
2169 parts->Add(ReplacementPart::SubjectPrefix());
2170 i = next_index;
2171 last = i + 1;
2172 break;
2173 case '\'':
2174 if (i > last) {
2175 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2176 }
2177 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2178 i = next_index;
2179 last = i + 1;
2180 break;
2181 case '&':
2182 if (i > last) {
2183 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2184 }
2185 parts->Add(ReplacementPart::SubjectMatch());
2186 i = next_index;
2187 last = i + 1;
2188 break;
2189 case '0':
2190 case '1':
2191 case '2':
2192 case '3':
2193 case '4':
2194 case '5':
2195 case '6':
2196 case '7':
2197 case '8':
2198 case '9': {
2199 int capture_ref = c2 - '0';
2200 if (capture_ref > capture_count) {
2201 i = next_index;
2202 continue;
2203 }
2204 int second_digit_index = next_index + 1;
2205 if (second_digit_index < length) {
2206 // Peek ahead to see if we have two digits.
2207 Char c3 = characters[second_digit_index];
2208 if ('0' <= c3 && c3 <= '9') { // Double digits.
2209 int double_digit_ref = capture_ref * 10 + c3 - '0';
2210 if (double_digit_ref <= capture_count) {
2211 next_index = second_digit_index;
2212 capture_ref = double_digit_ref;
2213 }
2214 }
2215 }
2216 if (capture_ref > 0) {
2217 if (i > last) {
2218 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2219 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002220 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002221 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2222 last = next_index + 1;
2223 }
2224 i = next_index;
2225 break;
2226 }
2227 default:
2228 i = next_index;
2229 break;
2230 }
2231 }
2232 }
2233 if (length > last) {
2234 if (last == 0) {
2235 parts->Add(ReplacementPart::ReplacementString());
2236 } else {
2237 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2238 }
2239 }
2240 }
2241
2242 ZoneList<ReplacementPart> parts_;
2243 ZoneList<Handle<String> > replacement_substrings_;
2244};
2245
2246
2247void CompiledReplacement::Compile(Handle<String> replacement,
2248 int capture_count,
2249 int subject_length) {
2250 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002251 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002252 AssertNoAllocation no_alloc;
2253 ParseReplacementPattern(&parts_,
2254 replacement->ToAsciiVector(),
2255 capture_count,
2256 subject_length);
2257 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002258 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002259 AssertNoAllocation no_alloc;
2260
2261 ParseReplacementPattern(&parts_,
2262 replacement->ToUC16Vector(),
2263 capture_count,
2264 subject_length);
2265 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002266 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002267 int substring_index = 0;
2268 for (int i = 0, n = parts_.length(); i < n; i++) {
2269 int tag = parts_[i].tag;
2270 if (tag <= 0) { // A replacement string slice.
2271 int from = -tag;
2272 int to = parts_[i].data;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002273 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002274 parts_[i].tag = REPLACEMENT_SUBSTRING;
2275 parts_[i].data = substring_index;
2276 substring_index++;
2277 } else if (tag == REPLACEMENT_STRING) {
2278 replacement_substrings_.Add(replacement);
2279 parts_[i].data = substring_index;
2280 substring_index++;
2281 }
2282 }
2283}
2284
2285
2286void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2287 int match_from,
2288 int match_to,
2289 Handle<JSArray> last_match_info) {
2290 for (int i = 0, n = parts_.length(); i < n; i++) {
2291 ReplacementPart part = parts_[i];
2292 switch (part.tag) {
2293 case SUBJECT_PREFIX:
2294 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2295 break;
2296 case SUBJECT_SUFFIX: {
2297 int subject_length = part.data;
2298 if (match_to < subject_length) {
2299 builder->AddSubjectSlice(match_to, subject_length);
2300 }
2301 break;
2302 }
2303 case SUBJECT_CAPTURE: {
2304 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002305 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002306 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2307 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2308 if (from >= 0 && to > from) {
2309 builder->AddSubjectSlice(from, to);
2310 }
2311 break;
2312 }
2313 case REPLACEMENT_SUBSTRING:
2314 case REPLACEMENT_STRING:
2315 builder->AddString(replacement_substrings_[part.data]);
2316 break;
2317 default:
2318 UNREACHABLE();
2319 }
2320 }
2321}
2322
2323
2324
lrn@chromium.org303ada72010-10-27 09:33:13 +00002325MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
2326 String* subject,
2327 JSRegExp* regexp,
2328 String* replacement,
2329 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002330 ASSERT(subject->IsFlat());
2331 ASSERT(replacement->IsFlat());
2332
2333 HandleScope handles;
2334
2335 int length = subject->length();
2336 Handle<String> subject_handle(subject);
2337 Handle<JSRegExp> regexp_handle(regexp);
2338 Handle<String> replacement_handle(replacement);
2339 Handle<JSArray> last_match_info_handle(last_match_info);
2340 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2341 subject_handle,
2342 0,
2343 last_match_info_handle);
2344 if (match.is_null()) {
2345 return Failure::Exception();
2346 }
2347 if (match->IsNull()) {
2348 return *subject_handle;
2349 }
2350
2351 int capture_count = regexp_handle->CaptureCount();
2352
2353 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002354 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002355 CompiledReplacement compiled_replacement;
2356 compiled_replacement.Compile(replacement_handle,
2357 capture_count,
2358 length);
2359
2360 bool is_global = regexp_handle->GetFlags().is_global();
2361
2362 // Guessing the number of parts that the final result string is built
2363 // from. Global regexps can match any number of times, so we guess
2364 // conservatively.
2365 int expected_parts =
2366 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
2367 ReplacementStringBuilder builder(subject_handle, expected_parts);
2368
2369 // Index of end of last match.
2370 int prev = 0;
2371
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002372 // Number of parts added by compiled replacement plus preceeding
2373 // string and possibly suffix after last match. It is possible for
2374 // all components to use two elements when encoded as two smis.
2375 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002376 bool matched = true;
2377 do {
2378 ASSERT(last_match_info_handle->HasFastElements());
2379 // Increase the capacity of the builder before entering local handle-scope,
2380 // so its internal buffer can safely allocate a new handle if it grows.
2381 builder.EnsureCapacity(parts_added_per_loop);
2382
2383 HandleScope loop_scope;
2384 int start, end;
2385 {
2386 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002387 FixedArray* match_info_array =
2388 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002389
2390 ASSERT_EQ(capture_count * 2 + 2,
2391 RegExpImpl::GetLastCaptureCount(match_info_array));
2392 start = RegExpImpl::GetCapture(match_info_array, 0);
2393 end = RegExpImpl::GetCapture(match_info_array, 1);
2394 }
2395
2396 if (prev < start) {
2397 builder.AddSubjectSlice(prev, start);
2398 }
2399 compiled_replacement.Apply(&builder,
2400 start,
2401 end,
2402 last_match_info_handle);
2403 prev = end;
2404
2405 // Only continue checking for global regexps.
2406 if (!is_global) break;
2407
2408 // Continue from where the match ended, unless it was an empty match.
2409 int next = end;
2410 if (start == end) {
2411 next = end + 1;
2412 if (next > length) break;
2413 }
2414
2415 match = RegExpImpl::Exec(regexp_handle,
2416 subject_handle,
2417 next,
2418 last_match_info_handle);
2419 if (match.is_null()) {
2420 return Failure::Exception();
2421 }
2422 matched = !match->IsNull();
2423 } while (matched);
2424
2425 if (prev < length) {
2426 builder.AddSubjectSlice(prev, length);
2427 }
2428
2429 return *(builder.ToString());
2430}
2431
2432
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002433template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002434MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
2435 String* subject,
2436 JSRegExp* regexp,
2437 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002438 ASSERT(subject->IsFlat());
2439
2440 HandleScope handles;
2441
2442 Handle<String> subject_handle(subject);
2443 Handle<JSRegExp> regexp_handle(regexp);
2444 Handle<JSArray> last_match_info_handle(last_match_info);
2445 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2446 subject_handle,
2447 0,
2448 last_match_info_handle);
2449 if (match.is_null()) return Failure::Exception();
2450 if (match->IsNull()) return *subject_handle;
2451
2452 ASSERT(last_match_info_handle->HasFastElements());
2453
2454 HandleScope loop_scope;
2455 int start, end;
2456 {
2457 AssertNoAllocation match_info_array_is_not_in_a_handle;
2458 FixedArray* match_info_array =
2459 FixedArray::cast(last_match_info_handle->elements());
2460
2461 start = RegExpImpl::GetCapture(match_info_array, 0);
2462 end = RegExpImpl::GetCapture(match_info_array, 1);
2463 }
2464
2465 int length = subject->length();
2466 int new_length = length - (end - start);
2467 if (new_length == 0) {
2468 return Heap::empty_string();
2469 }
2470 Handle<ResultSeqString> answer;
2471 if (ResultSeqString::kHasAsciiEncoding) {
2472 answer =
2473 Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
2474 } else {
2475 answer =
2476 Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
2477 }
2478
2479 // If the regexp isn't global, only match once.
2480 if (!regexp_handle->GetFlags().is_global()) {
2481 if (start > 0) {
2482 String::WriteToFlat(*subject_handle,
2483 answer->GetChars(),
2484 0,
2485 start);
2486 }
2487 if (end < length) {
2488 String::WriteToFlat(*subject_handle,
2489 answer->GetChars() + start,
2490 end,
2491 length);
2492 }
2493 return *answer;
2494 }
2495
2496 int prev = 0; // Index of end of last match.
2497 int next = 0; // Start of next search (prev unless last match was empty).
2498 int position = 0;
2499
2500 do {
2501 if (prev < start) {
2502 // Add substring subject[prev;start] to answer string.
2503 String::WriteToFlat(*subject_handle,
2504 answer->GetChars() + position,
2505 prev,
2506 start);
2507 position += start - prev;
2508 }
2509 prev = end;
2510 next = end;
2511 // Continue from where the match ended, unless it was an empty match.
2512 if (start == end) {
2513 next++;
2514 if (next > length) break;
2515 }
2516 match = RegExpImpl::Exec(regexp_handle,
2517 subject_handle,
2518 next,
2519 last_match_info_handle);
2520 if (match.is_null()) return Failure::Exception();
2521 if (match->IsNull()) break;
2522
2523 ASSERT(last_match_info_handle->HasFastElements());
2524 HandleScope loop_scope;
2525 {
2526 AssertNoAllocation match_info_array_is_not_in_a_handle;
2527 FixedArray* match_info_array =
2528 FixedArray::cast(last_match_info_handle->elements());
2529 start = RegExpImpl::GetCapture(match_info_array, 0);
2530 end = RegExpImpl::GetCapture(match_info_array, 1);
2531 }
2532 } while (true);
2533
2534 if (prev < length) {
2535 // Add substring subject[prev;length] to answer string.
2536 String::WriteToFlat(*subject_handle,
2537 answer->GetChars() + position,
2538 prev,
2539 length);
2540 position += length - prev;
2541 }
2542
2543 if (position == 0) {
2544 return Heap::empty_string();
2545 }
2546
2547 // Shorten string and fill
2548 int string_size = ResultSeqString::SizeFor(position);
2549 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2550 int delta = allocated_string_size - string_size;
2551
2552 answer->set_length(position);
2553 if (delta == 0) return *answer;
2554
2555 Address end_of_string = answer->address() + string_size;
2556 Heap::CreateFillerObjectAt(end_of_string, delta);
2557
2558 return *answer;
2559}
2560
2561
lrn@chromium.org303ada72010-10-27 09:33:13 +00002562static MaybeObject* Runtime_StringReplaceRegExpWithString(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002563 ASSERT(args.length() == 4);
2564
2565 CONVERT_CHECKED(String, subject, args[0]);
2566 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002567 Object* flat_subject;
2568 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2569 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2570 return maybe_flat_subject;
2571 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002572 }
2573 subject = String::cast(flat_subject);
2574 }
2575
2576 CONVERT_CHECKED(String, replacement, args[2]);
2577 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002578 Object* flat_replacement;
2579 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2580 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2581 return maybe_flat_replacement;
2582 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002583 }
2584 replacement = String::cast(flat_replacement);
2585 }
2586
2587 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2588 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2589
2590 ASSERT(last_match_info->HasFastElements());
2591
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002592 if (replacement->length() == 0) {
2593 if (subject->HasOnlyAsciiChars()) {
2594 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
2595 subject, regexp, last_match_info);
2596 } else {
2597 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
2598 subject, regexp, last_match_info);
2599 }
2600 }
2601
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002602 return StringReplaceRegExpWithString(subject,
2603 regexp,
2604 replacement,
2605 last_match_info);
2606}
2607
2608
ager@chromium.org7c537e22008-10-16 08:43:32 +00002609// Perform string match of pattern on subject, starting at start index.
2610// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002611// and should check that pat->length() + start_index <= sub->length().
ager@chromium.org7c537e22008-10-16 08:43:32 +00002612int Runtime::StringMatch(Handle<String> sub,
2613 Handle<String> pat,
2614 int start_index) {
2615 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002616 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002617
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002618 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002619 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002620
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002621 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002622 if (start_index + pattern_length > subject_length) return -1;
2623
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002624 if (!sub->IsFlat()) FlattenString(sub);
2625 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002626
ager@chromium.org7c537e22008-10-16 08:43:32 +00002627 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002628 // Extract flattened substrings of cons strings before determining asciiness.
2629 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002630 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002631 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002632 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002633
ager@chromium.org7c537e22008-10-16 08:43:32 +00002634 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002635 if (seq_pat->IsAsciiRepresentation()) {
2636 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2637 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002638 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002639 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002640 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002641 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002642 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2643 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002644 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002645 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002646 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002647}
2648
2649
lrn@chromium.org303ada72010-10-27 09:33:13 +00002650static MaybeObject* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002651 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002652 ASSERT(args.length() == 3);
2653
ager@chromium.org7c537e22008-10-16 08:43:32 +00002654 CONVERT_ARG_CHECKED(String, sub, 0);
2655 CONVERT_ARG_CHECKED(String, pat, 1);
2656
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002657 Object* index = args[2];
2658 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002659 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002660
ager@chromium.org870a0b62008-11-04 11:43:05 +00002661 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002662 int position = Runtime::StringMatch(sub, pat, start_index);
2663 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002664}
2665
2666
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002667template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002668static int StringMatchBackwards(Vector<const schar> subject,
2669 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002670 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002671 int pattern_length = pattern.length();
2672 ASSERT(pattern_length >= 1);
2673 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002674
2675 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002676 for (int i = 0; i < pattern_length; i++) {
2677 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002678 if (c > String::kMaxAsciiCharCode) {
2679 return -1;
2680 }
2681 }
2682 }
2683
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002684 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002685 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002686 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002687 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002688 while (j < pattern_length) {
2689 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002690 break;
2691 }
2692 j++;
2693 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002694 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002695 return i;
2696 }
2697 }
2698 return -1;
2699}
2700
lrn@chromium.org303ada72010-10-27 09:33:13 +00002701static MaybeObject* Runtime_StringLastIndexOf(Arguments args) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002702 HandleScope scope; // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002703 ASSERT(args.length() == 3);
2704
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002705 CONVERT_ARG_CHECKED(String, sub, 0);
2706 CONVERT_ARG_CHECKED(String, pat, 1);
2707
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002708 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002709 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002710 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002711
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002712 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002713 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002714
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002715 if (start_index + pat_length > sub_length) {
2716 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002717 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002718
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002719 if (pat_length == 0) {
2720 return Smi::FromInt(start_index);
2721 }
2722
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002723 if (!sub->IsFlat()) FlattenString(sub);
2724 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002725
2726 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2727
2728 int position = -1;
2729
2730 if (pat->IsAsciiRepresentation()) {
2731 Vector<const char> pat_vector = pat->ToAsciiVector();
2732 if (sub->IsAsciiRepresentation()) {
2733 position = StringMatchBackwards(sub->ToAsciiVector(),
2734 pat_vector,
2735 start_index);
2736 } else {
2737 position = StringMatchBackwards(sub->ToUC16Vector(),
2738 pat_vector,
2739 start_index);
2740 }
2741 } else {
2742 Vector<const uc16> pat_vector = pat->ToUC16Vector();
2743 if (sub->IsAsciiRepresentation()) {
2744 position = StringMatchBackwards(sub->ToAsciiVector(),
2745 pat_vector,
2746 start_index);
2747 } else {
2748 position = StringMatchBackwards(sub->ToUC16Vector(),
2749 pat_vector,
2750 start_index);
2751 }
2752 }
2753
2754 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002755}
2756
2757
lrn@chromium.org303ada72010-10-27 09:33:13 +00002758static MaybeObject* Runtime_StringLocaleCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002759 NoHandleAllocation ha;
2760 ASSERT(args.length() == 2);
2761
2762 CONVERT_CHECKED(String, str1, args[0]);
2763 CONVERT_CHECKED(String, str2, args[1]);
2764
2765 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002766 int str1_length = str1->length();
2767 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002768
2769 // Decide trivial cases without flattening.
2770 if (str1_length == 0) {
2771 if (str2_length == 0) return Smi::FromInt(0); // Equal.
2772 return Smi::FromInt(-str2_length);
2773 } else {
2774 if (str2_length == 0) return Smi::FromInt(str1_length);
2775 }
2776
2777 int end = str1_length < str2_length ? str1_length : str2_length;
2778
2779 // No need to flatten if we are going to find the answer on the first
2780 // character. At this point we know there is at least one character
2781 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002782 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002783 if (d != 0) return Smi::FromInt(d);
2784
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002785 str1->TryFlatten();
2786 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002787
2788 static StringInputBuffer buf1;
2789 static StringInputBuffer buf2;
2790
2791 buf1.Reset(str1);
2792 buf2.Reset(str2);
2793
2794 for (int i = 0; i < end; i++) {
2795 uint16_t char1 = buf1.GetNext();
2796 uint16_t char2 = buf2.GetNext();
2797 if (char1 != char2) return Smi::FromInt(char1 - char2);
2798 }
2799
2800 return Smi::FromInt(str1_length - str2_length);
2801}
2802
2803
lrn@chromium.org303ada72010-10-27 09:33:13 +00002804static MaybeObject* Runtime_SubString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002805 NoHandleAllocation ha;
2806 ASSERT(args.length() == 3);
2807
2808 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002809 Object* from = args[1];
2810 Object* to = args[2];
2811 int start, end;
2812 // We have a fast integer-only case here to avoid a conversion to double in
2813 // the common case where from and to are Smis.
2814 if (from->IsSmi() && to->IsSmi()) {
2815 start = Smi::cast(from)->value();
2816 end = Smi::cast(to)->value();
2817 } else {
2818 CONVERT_DOUBLE_CHECKED(from_number, from);
2819 CONVERT_DOUBLE_CHECKED(to_number, to);
2820 start = FastD2I(from_number);
2821 end = FastD2I(to_number);
2822 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002823 RUNTIME_ASSERT(end >= start);
2824 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002825 RUNTIME_ASSERT(end <= value->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002826 Counters::sub_string_runtime.Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002827 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002828}
2829
2830
lrn@chromium.org303ada72010-10-27 09:33:13 +00002831static MaybeObject* Runtime_StringMatch(Arguments args) {
ager@chromium.org41826e72009-03-30 13:30:57 +00002832 ASSERT_EQ(3, args.length());
2833
2834 CONVERT_ARG_CHECKED(String, subject, 0);
2835 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
2836 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
2837 HandleScope handles;
2838
2839 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
2840
2841 if (match.is_null()) {
2842 return Failure::Exception();
2843 }
2844 if (match->IsNull()) {
2845 return Heap::null_value();
2846 }
2847 int length = subject->length();
2848
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002849 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00002850 ZoneList<int> offsets(8);
2851 do {
2852 int start;
2853 int end;
2854 {
2855 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002856 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00002857 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
2858 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
2859 }
2860 offsets.Add(start);
2861 offsets.Add(end);
2862 int index = start < end ? end : end + 1;
2863 if (index > length) break;
2864 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
2865 if (match.is_null()) {
2866 return Failure::Exception();
2867 }
2868 } while (!match->IsNull());
2869 int matches = offsets.length() / 2;
2870 Handle<FixedArray> elements = Factory::NewFixedArray(matches);
2871 for (int i = 0; i < matches ; i++) {
2872 int from = offsets.at(i * 2);
2873 int to = offsets.at(i * 2 + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002874 Handle<String> match = Factory::NewSubString(subject, from, to);
2875 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00002876 }
2877 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
2878 result->set_length(Smi::FromInt(matches));
2879 return *result;
2880}
2881
2882
lrn@chromium.org25156de2010-04-06 13:10:27 +00002883// Two smis before and after the match, for very long strings.
2884const int kMaxBuilderEntriesPerRegExpMatch = 5;
2885
2886
2887static void SetLastMatchInfoNoCaptures(Handle<String> subject,
2888 Handle<JSArray> last_match_info,
2889 int match_start,
2890 int match_end) {
2891 // Fill last_match_info with a single capture.
2892 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
2893 AssertNoAllocation no_gc;
2894 FixedArray* elements = FixedArray::cast(last_match_info->elements());
2895 RegExpImpl::SetLastCaptureCount(elements, 2);
2896 RegExpImpl::SetLastInput(elements, *subject);
2897 RegExpImpl::SetLastSubject(elements, *subject);
2898 RegExpImpl::SetCapture(elements, 0, match_start);
2899 RegExpImpl::SetCapture(elements, 1, match_end);
2900}
2901
2902
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002903template <typename SubjectChar, typename PatternChar>
2904static bool SearchStringMultiple(Vector<const SubjectChar> subject,
2905 Vector<const PatternChar> pattern,
2906 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002907 FixedArrayBuilder* builder,
2908 int* match_pos) {
2909 int pos = *match_pos;
2910 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002911 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002912 int max_search_start = subject_length - pattern_length;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002913 StringSearch<PatternChar, SubjectChar> search(pattern);
2914 while (pos <= max_search_start) {
2915 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
2916 *match_pos = pos;
2917 return false;
2918 }
2919 // Position of end of previous match.
2920 int match_end = pos + pattern_length;
2921 int new_pos = search.Search(subject, match_end);
2922 if (new_pos >= 0) {
2923 // A match.
2924 if (new_pos > match_end) {
2925 ReplacementStringBuilder::AddSubjectSlice(builder,
2926 match_end,
2927 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002928 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002929 pos = new_pos;
2930 builder->Add(pattern_string);
2931 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002932 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002933 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002934 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002935
lrn@chromium.org25156de2010-04-06 13:10:27 +00002936 if (pos < max_search_start) {
2937 ReplacementStringBuilder::AddSubjectSlice(builder,
2938 pos + pattern_length,
2939 subject_length);
2940 }
2941 *match_pos = pos;
2942 return true;
2943}
2944
2945
2946static bool SearchStringMultiple(Handle<String> subject,
2947 Handle<String> pattern,
2948 Handle<JSArray> last_match_info,
2949 FixedArrayBuilder* builder) {
2950 ASSERT(subject->IsFlat());
2951 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002952
2953 // Treating as if a previous match was before first character.
2954 int match_pos = -pattern->length();
2955
2956 for (;;) { // Break when search complete.
2957 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
2958 AssertNoAllocation no_gc;
2959 if (subject->IsAsciiRepresentation()) {
2960 Vector<const char> subject_vector = subject->ToAsciiVector();
2961 if (pattern->IsAsciiRepresentation()) {
2962 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002963 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002964 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002965 builder,
2966 &match_pos)) break;
2967 } else {
2968 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002969 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002970 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002971 builder,
2972 &match_pos)) break;
2973 }
2974 } else {
2975 Vector<const uc16> subject_vector = subject->ToUC16Vector();
2976 if (pattern->IsAsciiRepresentation()) {
2977 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002978 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002979 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002980 builder,
2981 &match_pos)) break;
2982 } else {
2983 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002984 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002985 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002986 builder,
2987 &match_pos)) break;
2988 }
2989 }
2990 }
2991
2992 if (match_pos >= 0) {
2993 SetLastMatchInfoNoCaptures(subject,
2994 last_match_info,
2995 match_pos,
2996 match_pos + pattern->length());
2997 return true;
2998 }
2999 return false; // No matches at all.
3000}
3001
3002
3003static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
3004 Handle<String> subject,
3005 Handle<JSRegExp> regexp,
3006 Handle<JSArray> last_match_array,
3007 FixedArrayBuilder* builder) {
3008 ASSERT(subject->IsFlat());
3009 int match_start = -1;
3010 int match_end = 0;
3011 int pos = 0;
3012 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3013 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3014
3015 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003016 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003017 int subject_length = subject->length();
3018
3019 for (;;) { // Break on failure, return on exception.
3020 RegExpImpl::IrregexpResult result =
3021 RegExpImpl::IrregexpExecOnce(regexp,
3022 subject,
3023 pos,
3024 register_vector);
3025 if (result == RegExpImpl::RE_SUCCESS) {
3026 match_start = register_vector[0];
3027 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3028 if (match_end < match_start) {
3029 ReplacementStringBuilder::AddSubjectSlice(builder,
3030 match_end,
3031 match_start);
3032 }
3033 match_end = register_vector[1];
3034 HandleScope loop_scope;
3035 builder->Add(*Factory::NewSubString(subject, match_start, match_end));
3036 if (match_start != match_end) {
3037 pos = match_end;
3038 } else {
3039 pos = match_end + 1;
3040 if (pos > subject_length) break;
3041 }
3042 } else if (result == RegExpImpl::RE_FAILURE) {
3043 break;
3044 } else {
3045 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3046 return result;
3047 }
3048 }
3049
3050 if (match_start >= 0) {
3051 if (match_end < subject_length) {
3052 ReplacementStringBuilder::AddSubjectSlice(builder,
3053 match_end,
3054 subject_length);
3055 }
3056 SetLastMatchInfoNoCaptures(subject,
3057 last_match_array,
3058 match_start,
3059 match_end);
3060 return RegExpImpl::RE_SUCCESS;
3061 } else {
3062 return RegExpImpl::RE_FAILURE; // No matches at all.
3063 }
3064}
3065
3066
3067static RegExpImpl::IrregexpResult SearchRegExpMultiple(
3068 Handle<String> subject,
3069 Handle<JSRegExp> regexp,
3070 Handle<JSArray> last_match_array,
3071 FixedArrayBuilder* builder) {
3072
3073 ASSERT(subject->IsFlat());
3074 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3075 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3076
3077 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003078 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003079
3080 RegExpImpl::IrregexpResult result =
3081 RegExpImpl::IrregexpExecOnce(regexp,
3082 subject,
3083 0,
3084 register_vector);
3085
3086 int capture_count = regexp->CaptureCount();
3087 int subject_length = subject->length();
3088
3089 // Position to search from.
3090 int pos = 0;
3091 // End of previous match. Differs from pos if match was empty.
3092 int match_end = 0;
3093 if (result == RegExpImpl::RE_SUCCESS) {
3094 // Need to keep a copy of the previous match for creating last_match_info
3095 // at the end, so we have two vectors that we swap between.
3096 OffsetsVector registers2(required_registers);
3097 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3098
3099 do {
3100 int match_start = register_vector[0];
3101 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3102 if (match_end < match_start) {
3103 ReplacementStringBuilder::AddSubjectSlice(builder,
3104 match_end,
3105 match_start);
3106 }
3107 match_end = register_vector[1];
3108
3109 {
3110 // Avoid accumulating new handles inside loop.
3111 HandleScope temp_scope;
3112 // Arguments array to replace function is match, captures, index and
3113 // subject, i.e., 3 + capture count in total.
3114 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003115 Handle<String> match = Factory::NewSubString(subject,
3116 match_start,
3117 match_end);
3118 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003119 for (int i = 1; i <= capture_count; i++) {
3120 int start = register_vector[i * 2];
3121 if (start >= 0) {
3122 int end = register_vector[i * 2 + 1];
3123 ASSERT(start <= end);
3124 Handle<String> substring = Factory::NewSubString(subject,
3125 start,
3126 end);
3127 elements->set(i, *substring);
3128 } else {
3129 ASSERT(register_vector[i * 2 + 1] < 0);
3130 elements->set(i, Heap::undefined_value());
3131 }
3132 }
3133 elements->set(capture_count + 1, Smi::FromInt(match_start));
3134 elements->set(capture_count + 2, *subject);
3135 builder->Add(*Factory::NewJSArrayWithElements(elements));
3136 }
3137 // Swap register vectors, so the last successful match is in
3138 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003139 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003140 prev_register_vector = register_vector;
3141 register_vector = tmp;
3142
3143 if (match_end > match_start) {
3144 pos = match_end;
3145 } else {
3146 pos = match_end + 1;
3147 if (pos > subject_length) {
3148 break;
3149 }
3150 }
3151
3152 result = RegExpImpl::IrregexpExecOnce(regexp,
3153 subject,
3154 pos,
3155 register_vector);
3156 } while (result == RegExpImpl::RE_SUCCESS);
3157
3158 if (result != RegExpImpl::RE_EXCEPTION) {
3159 // Finished matching, with at least one match.
3160 if (match_end < subject_length) {
3161 ReplacementStringBuilder::AddSubjectSlice(builder,
3162 match_end,
3163 subject_length);
3164 }
3165
3166 int last_match_capture_count = (capture_count + 1) * 2;
3167 int last_match_array_size =
3168 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3169 last_match_array->EnsureSize(last_match_array_size);
3170 AssertNoAllocation no_gc;
3171 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3172 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3173 RegExpImpl::SetLastSubject(elements, *subject);
3174 RegExpImpl::SetLastInput(elements, *subject);
3175 for (int i = 0; i < last_match_capture_count; i++) {
3176 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3177 }
3178 return RegExpImpl::RE_SUCCESS;
3179 }
3180 }
3181 // No matches at all, return failure or exception result directly.
3182 return result;
3183}
3184
3185
lrn@chromium.org303ada72010-10-27 09:33:13 +00003186static MaybeObject* Runtime_RegExpExecMultiple(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003187 ASSERT(args.length() == 4);
3188 HandleScope handles;
3189
3190 CONVERT_ARG_CHECKED(String, subject, 1);
3191 if (!subject->IsFlat()) { FlattenString(subject); }
3192 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3193 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3194 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3195
3196 ASSERT(last_match_info->HasFastElements());
3197 ASSERT(regexp->GetFlags().is_global());
3198 Handle<FixedArray> result_elements;
3199 if (result_array->HasFastElements()) {
3200 result_elements =
3201 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3202 } else {
3203 result_elements = Factory::NewFixedArrayWithHoles(16);
3204 }
3205 FixedArrayBuilder builder(result_elements);
3206
3207 if (regexp->TypeTag() == JSRegExp::ATOM) {
3208 Handle<String> pattern(
3209 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003210 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003211 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
3212 return *builder.ToJSArray(result_array);
3213 }
3214 return Heap::null_value();
3215 }
3216
3217 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3218
3219 RegExpImpl::IrregexpResult result;
3220 if (regexp->CaptureCount() == 0) {
3221 result = SearchRegExpNoCaptureMultiple(subject,
3222 regexp,
3223 last_match_info,
3224 &builder);
3225 } else {
3226 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
3227 }
3228 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
3229 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
3230 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3231 return Failure::Exception();
3232}
3233
3234
lrn@chromium.org303ada72010-10-27 09:33:13 +00003235static MaybeObject* Runtime_NumberToRadixString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003236 NoHandleAllocation ha;
3237 ASSERT(args.length() == 2);
3238
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003239 // Fast case where the result is a one character string.
3240 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3241 int value = Smi::cast(args[0])->value();
3242 int radix = Smi::cast(args[1])->value();
3243 if (value >= 0 && value < radix) {
3244 RUNTIME_ASSERT(radix <= 36);
3245 // Character array used for conversion.
3246 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
3247 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]);
3248 }
3249 }
3250
3251 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003252 CONVERT_DOUBLE_CHECKED(value, args[0]);
3253 if (isnan(value)) {
3254 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3255 }
3256 if (isinf(value)) {
3257 if (value < 0) {
3258 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3259 }
3260 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3261 }
3262 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3263 int radix = FastD2I(radix_number);
3264 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3265 char* str = DoubleToRadixCString(value, radix);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003266 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003267 DeleteArray(str);
3268 return result;
3269}
3270
3271
lrn@chromium.org303ada72010-10-27 09:33:13 +00003272static MaybeObject* Runtime_NumberToFixed(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003273 NoHandleAllocation ha;
3274 ASSERT(args.length() == 2);
3275
3276 CONVERT_DOUBLE_CHECKED(value, args[0]);
3277 if (isnan(value)) {
3278 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3279 }
3280 if (isinf(value)) {
3281 if (value < 0) {
3282 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3283 }
3284 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3285 }
3286 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3287 int f = FastD2I(f_number);
3288 RUNTIME_ASSERT(f >= 0);
3289 char* str = DoubleToFixedCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003290 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003291 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003292 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003293}
3294
3295
lrn@chromium.org303ada72010-10-27 09:33:13 +00003296static MaybeObject* Runtime_NumberToExponential(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003297 NoHandleAllocation ha;
3298 ASSERT(args.length() == 2);
3299
3300 CONVERT_DOUBLE_CHECKED(value, args[0]);
3301 if (isnan(value)) {
3302 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3303 }
3304 if (isinf(value)) {
3305 if (value < 0) {
3306 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3307 }
3308 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3309 }
3310 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3311 int f = FastD2I(f_number);
3312 RUNTIME_ASSERT(f >= -1 && f <= 20);
3313 char* str = DoubleToExponentialCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003314 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003315 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003316 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003317}
3318
3319
lrn@chromium.org303ada72010-10-27 09:33:13 +00003320static MaybeObject* Runtime_NumberToPrecision(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003321 NoHandleAllocation ha;
3322 ASSERT(args.length() == 2);
3323
3324 CONVERT_DOUBLE_CHECKED(value, args[0]);
3325 if (isnan(value)) {
3326 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3327 }
3328 if (isinf(value)) {
3329 if (value < 0) {
3330 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3331 }
3332 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3333 }
3334 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3335 int f = FastD2I(f_number);
3336 RUNTIME_ASSERT(f >= 1 && f <= 21);
3337 char* str = DoubleToPrecisionCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003338 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003339 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003340 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003341}
3342
3343
3344// Returns a single character string where first character equals
3345// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003346static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003347 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003348 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003349 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003350 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003351 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003352 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003353}
3354
3355
lrn@chromium.org303ada72010-10-27 09:33:13 +00003356MaybeObject* Runtime::GetElementOrCharAt(Handle<Object> object,
3357 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003358 // Handle [] indexing on Strings
3359 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003360 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3361 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003362 }
3363
3364 // Handle [] indexing on String objects
3365 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003366 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3367 Handle<Object> result =
3368 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3369 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003370 }
3371
3372 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003373 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003374 return prototype->GetElement(index);
3375 }
3376
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003377 return GetElement(object, index);
3378}
3379
3380
lrn@chromium.org303ada72010-10-27 09:33:13 +00003381MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003382 return object->GetElement(index);
3383}
3384
3385
lrn@chromium.org303ada72010-10-27 09:33:13 +00003386MaybeObject* Runtime::GetObjectProperty(Handle<Object> object,
3387 Handle<Object> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003388 HandleScope scope;
3389
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003390 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003391 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003392 Handle<Object> error =
3393 Factory::NewTypeError("non_object_property_load",
3394 HandleVector(args, 2));
3395 return Top::Throw(*error);
3396 }
3397
3398 // Check if the given key is an array index.
3399 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003400 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003401 return GetElementOrCharAt(object, index);
3402 }
3403
3404 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003405 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003406 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003407 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003408 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003409 bool has_pending_exception = false;
3410 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003411 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003412 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003413 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003414 }
3415
ager@chromium.org32912102009-01-16 10:38:43 +00003416 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003417 // the element if so.
3418 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003419 return GetElementOrCharAt(object, index);
3420 } else {
3421 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003422 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003423 }
3424}
3425
3426
lrn@chromium.org303ada72010-10-27 09:33:13 +00003427static MaybeObject* Runtime_GetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003428 NoHandleAllocation ha;
3429 ASSERT(args.length() == 2);
3430
3431 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003432 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003433
3434 return Runtime::GetObjectProperty(object, key);
3435}
3436
3437
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003438// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003439static MaybeObject* Runtime_KeyedGetProperty(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003440 NoHandleAllocation ha;
3441 ASSERT(args.length() == 2);
3442
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003443 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003444 // itself.
3445 //
3446 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003447 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003448 // global proxy object never has properties. This is the case
3449 // because the global proxy object forwards everything to its hidden
3450 // prototype including local lookups.
3451 //
3452 // Additionally, we need to make sure that we do not cache results
3453 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003454 if (args[0]->IsJSObject() &&
3455 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003456 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003457 args[1]->IsString()) {
3458 JSObject* receiver = JSObject::cast(args[0]);
3459 String* key = String::cast(args[1]);
3460 if (receiver->HasFastProperties()) {
3461 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003462 Map* receiver_map = receiver->map();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003463 int offset = KeyedLookupCache::Lookup(receiver_map, key);
3464 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003465 Object* value = receiver->FastPropertyAt(offset);
3466 return value->IsTheHole() ? Heap::undefined_value() : value;
3467 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003468 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003469 LookupResult result;
3470 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003471 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003472 int offset = result.GetFieldIndex();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003473 KeyedLookupCache::Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003474 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003475 }
3476 } else {
3477 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003478 StringDictionary* dictionary = receiver->property_dictionary();
3479 int entry = dictionary->FindEntry(key);
3480 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003481 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003482 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003483 if (!receiver->IsGlobalObject()) return value;
3484 value = JSGlobalPropertyCell::cast(value)->value();
3485 if (!value->IsTheHole()) return value;
3486 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003487 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003488 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003489 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3490 // Fast case for string indexing using [] with a smi index.
3491 HandleScope scope;
3492 Handle<String> str = args.at<String>(0);
3493 int index = Smi::cast(args[1])->value();
3494 Handle<Object> result = GetCharAt(str, index);
3495 return *result;
ager@chromium.org7c537e22008-10-16 08:43:32 +00003496 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003497
3498 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003499 return Runtime::GetObjectProperty(args.at<Object>(0),
3500 args.at<Object>(1));
3501}
3502
3503
lrn@chromium.org303ada72010-10-27 09:33:13 +00003504static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003505 ASSERT(args.length() == 5);
3506 HandleScope scope;
3507 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3508 CONVERT_CHECKED(String, name, args[1]);
3509 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003510 Object* fun = args[3];
3511 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003512 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3513 int unchecked = flag_attr->value();
3514 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3515 RUNTIME_ASSERT(!obj->IsNull());
3516 LookupResult result;
3517 obj->LocalLookupRealNamedProperty(name, &result);
3518
3519 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3520 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3521 // delete it to avoid running into trouble in DefineAccessor, which
3522 // handles this incorrectly if the property is readonly (does nothing)
3523 if (result.IsProperty() &&
3524 (result.type() == FIELD || result.type() == NORMAL
3525 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003526 Object* ok;
3527 { MaybeObject* maybe_ok =
3528 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3529 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3530 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003531 }
3532 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3533}
3534
lrn@chromium.org303ada72010-10-27 09:33:13 +00003535static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003536 ASSERT(args.length() == 4);
3537 HandleScope scope;
3538 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3539 CONVERT_ARG_CHECKED(String, name, 1);
3540 Handle<Object> obj_value = args.at<Object>(2);
3541
3542 CONVERT_CHECKED(Smi, flag, args[3]);
3543 int unchecked = flag->value();
3544 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3545
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003546 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3547
3548 // Check if this is an element.
3549 uint32_t index;
3550 bool is_element = name->AsArrayIndex(&index);
3551
3552 // Special case for elements if any of the flags are true.
3553 // If elements are in fast case we always implicitly assume that:
3554 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3555 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3556 is_element) {
3557 // Normalize the elements to enable attributes on the property.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003558 NormalizeElements(js_object);
3559 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003560 // Make sure that we never go back to fast case.
3561 dictionary->set_requires_slow_elements();
3562 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003563 NumberDictionarySet(dictionary, index, obj_value, details);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003564 }
3565
ager@chromium.org5c838252010-02-19 08:53:10 +00003566 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003567 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003568
ager@chromium.org5c838252010-02-19 08:53:10 +00003569 // Take special care when attributes are different and there is already
3570 // a property. For simplicity we normalize the property which enables us
3571 // to not worry about changing the instance_descriptor and creating a new
3572 // map. The current version of SetObjectProperty does not handle attributes
3573 // correctly in the case where a property is a field and is reset with
3574 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003575 if (result.IsProperty() &&
3576 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003577 // New attributes - normalize to avoid writing to instance descriptor
lrn@chromium.org303ada72010-10-27 09:33:13 +00003578 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003579 // Use IgnoreAttributes version since a readonly property may be
3580 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003581 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3582 *obj_value,
3583 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003584 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003585
ager@chromium.org5c838252010-02-19 08:53:10 +00003586 return Runtime::SetObjectProperty(js_object, name, obj_value, attr);
3587}
3588
3589
lrn@chromium.org303ada72010-10-27 09:33:13 +00003590MaybeObject* Runtime::SetObjectProperty(Handle<Object> object,
3591 Handle<Object> key,
3592 Handle<Object> value,
3593 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003594 HandleScope scope;
3595
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003596 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003597 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003598 Handle<Object> error =
3599 Factory::NewTypeError("non_object_property_store",
3600 HandleVector(args, 2));
3601 return Top::Throw(*error);
3602 }
3603
3604 // If the object isn't a JavaScript object, we ignore the store.
3605 if (!object->IsJSObject()) return *value;
3606
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003607 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3608
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003609 // Check if the given key is an array index.
3610 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003611 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003612 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3613 // of a string using [] notation. We need to support this too in
3614 // JavaScript.
3615 // In the case of a String object we just need to redirect the assignment to
3616 // the underlying string if the index is in range. Since the underlying
3617 // string does nothing with the assignment then we can ignore such
3618 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003619 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003620 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003621 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003622
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003623 Handle<Object> result = SetElement(js_object, index, value);
3624 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003625 return *value;
3626 }
3627
3628 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003629 Handle<Object> result;
3630 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003631 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003632 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003633 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003634 key_string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003635 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003636 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003637 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003638 return *value;
3639 }
3640
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003641 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003642 bool has_pending_exception = false;
3643 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3644 if (has_pending_exception) return Failure::Exception();
3645 Handle<String> name = Handle<String>::cast(converted);
3646
3647 if (name->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003648 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003649 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003650 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003651 }
3652}
3653
3654
lrn@chromium.org303ada72010-10-27 09:33:13 +00003655MaybeObject* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
3656 Handle<Object> key,
3657 Handle<Object> value,
3658 PropertyAttributes attr) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003659 HandleScope scope;
3660
3661 // Check if the given key is an array index.
3662 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003663 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003664 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3665 // of a string using [] notation. We need to support this too in
3666 // JavaScript.
3667 // In the case of a String object we just need to redirect the assignment to
3668 // the underlying string if the index is in range. Since the underlying
3669 // string does nothing with the assignment then we can ignore such
3670 // assignments.
3671 if (js_object->IsStringObjectWithCharacterAt(index)) {
3672 return *value;
3673 }
3674
3675 return js_object->SetElement(index, *value);
3676 }
3677
3678 if (key->IsString()) {
3679 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003680 return js_object->SetElement(index, *value);
3681 } else {
3682 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003683 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003684 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
3685 *value,
3686 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003687 }
3688 }
3689
3690 // Call-back into JavaScript to convert the key to a string.
3691 bool has_pending_exception = false;
3692 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3693 if (has_pending_exception) return Failure::Exception();
3694 Handle<String> name = Handle<String>::cast(converted);
3695
3696 if (name->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003697 return js_object->SetElement(index, *value);
3698 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003699 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003700 }
3701}
3702
3703
lrn@chromium.org303ada72010-10-27 09:33:13 +00003704MaybeObject* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
3705 Handle<Object> key) {
ager@chromium.orge2902be2009-06-08 12:21:35 +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.orge2902be2009-06-08 12:21:35 +00003711 // In Firefox/SpiderMonkey, Safari and Opera you can access the
3712 // characters of a string using [] notation. In the case of a
3713 // String object we just need to redirect the deletion to the
3714 // underlying string if the index is in range. Since the
3715 // underlying string does nothing with the deletion, we can ignore
3716 // such deletions.
3717 if (js_object->IsStringObjectWithCharacterAt(index)) {
3718 return Heap::true_value();
3719 }
3720
3721 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
3722 }
3723
3724 Handle<String> key_string;
3725 if (key->IsString()) {
3726 key_string = Handle<String>::cast(key);
3727 } else {
3728 // Call-back into JavaScript to convert the key to a string.
3729 bool has_pending_exception = false;
3730 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3731 if (has_pending_exception) return Failure::Exception();
3732 key_string = Handle<String>::cast(converted);
3733 }
3734
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003735 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003736 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
3737}
3738
3739
lrn@chromium.org303ada72010-10-27 09:33:13 +00003740static MaybeObject* Runtime_SetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003741 NoHandleAllocation ha;
3742 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
3743
3744 Handle<Object> object = args.at<Object>(0);
3745 Handle<Object> key = args.at<Object>(1);
3746 Handle<Object> value = args.at<Object>(2);
3747
3748 // Compute attributes.
3749 PropertyAttributes attributes = NONE;
3750 if (args.length() == 4) {
3751 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003752 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003753 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003754 RUNTIME_ASSERT(
3755 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3756 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003757 }
3758 return Runtime::SetObjectProperty(object, key, value, attributes);
3759}
3760
3761
3762// Set a local property, even if it is READ_ONLY. If the property does not
3763// exist, it will be added with attributes NONE.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003764static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003765 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003766 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003767 CONVERT_CHECKED(JSObject, object, args[0]);
3768 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003769 // Compute attributes.
3770 PropertyAttributes attributes = NONE;
3771 if (args.length() == 4) {
3772 CONVERT_CHECKED(Smi, value_obj, args[3]);
3773 int unchecked_value = value_obj->value();
3774 // Only attribute bits should be set.
3775 RUNTIME_ASSERT(
3776 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3777 attributes = static_cast<PropertyAttributes>(unchecked_value);
3778 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003779
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003780 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003781 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003782}
3783
3784
lrn@chromium.org303ada72010-10-27 09:33:13 +00003785static MaybeObject* Runtime_DeleteProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003786 NoHandleAllocation ha;
3787 ASSERT(args.length() == 2);
3788
3789 CONVERT_CHECKED(JSObject, object, args[0]);
3790 CONVERT_CHECKED(String, key, args[1]);
ager@chromium.orge2902be2009-06-08 12:21:35 +00003791 return object->DeleteProperty(key, JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003792}
3793
3794
ager@chromium.org9085a012009-05-11 19:22:57 +00003795static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
3796 Handle<String> key) {
3797 if (object->HasLocalProperty(*key)) return Heap::true_value();
3798 // Handle hidden prototypes. If there's a hidden prototype above this thing
3799 // then we have to check it for properties, because they are supposed to
3800 // look like they are on this object.
3801 Handle<Object> proto(object->GetPrototype());
3802 if (proto->IsJSObject() &&
3803 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
3804 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
3805 }
3806 return Heap::false_value();
3807}
3808
3809
lrn@chromium.org303ada72010-10-27 09:33:13 +00003810static MaybeObject* Runtime_HasLocalProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003811 NoHandleAllocation ha;
3812 ASSERT(args.length() == 2);
3813 CONVERT_CHECKED(String, key, args[1]);
3814
ager@chromium.org9085a012009-05-11 19:22:57 +00003815 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003816 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00003817 if (obj->IsJSObject()) {
3818 JSObject* object = JSObject::cast(obj);
3819 // Fast case - no interceptors.
3820 if (object->HasRealNamedProperty(key)) return Heap::true_value();
3821 // Slow case. Either it's not there or we have an interceptor. We should
3822 // have handles for this kind of deal.
3823 HandleScope scope;
3824 return HasLocalPropertyImplementation(Handle<JSObject>(object),
3825 Handle<String>(key));
3826 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003827 // Well, there is one exception: Handle [] on strings.
3828 uint32_t index;
3829 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00003830 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003831 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003832 return Heap::true_value();
3833 }
3834 }
3835 return Heap::false_value();
3836}
3837
3838
lrn@chromium.org303ada72010-10-27 09:33:13 +00003839static MaybeObject* Runtime_HasProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003840 NoHandleAllocation na;
3841 ASSERT(args.length() == 2);
3842
3843 // Only JS objects can have properties.
3844 if (args[0]->IsJSObject()) {
3845 JSObject* object = JSObject::cast(args[0]);
3846 CONVERT_CHECKED(String, key, args[1]);
3847 if (object->HasProperty(key)) return Heap::true_value();
3848 }
3849 return Heap::false_value();
3850}
3851
3852
lrn@chromium.org303ada72010-10-27 09:33:13 +00003853static MaybeObject* Runtime_HasElement(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003854 NoHandleAllocation na;
3855 ASSERT(args.length() == 2);
3856
3857 // Only JS objects can have elements.
3858 if (args[0]->IsJSObject()) {
3859 JSObject* object = JSObject::cast(args[0]);
3860 CONVERT_CHECKED(Smi, index_obj, args[1]);
3861 uint32_t index = index_obj->value();
3862 if (object->HasElement(index)) return Heap::true_value();
3863 }
3864 return Heap::false_value();
3865}
3866
3867
lrn@chromium.org303ada72010-10-27 09:33:13 +00003868static MaybeObject* Runtime_IsPropertyEnumerable(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003869 NoHandleAllocation ha;
3870 ASSERT(args.length() == 2);
3871
3872 CONVERT_CHECKED(JSObject, object, args[0]);
3873 CONVERT_CHECKED(String, key, args[1]);
3874
3875 uint32_t index;
3876 if (key->AsArrayIndex(&index)) {
3877 return Heap::ToBoolean(object->HasElement(index));
3878 }
3879
ager@chromium.org870a0b62008-11-04 11:43:05 +00003880 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
3881 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003882}
3883
3884
lrn@chromium.org303ada72010-10-27 09:33:13 +00003885static MaybeObject* Runtime_GetPropertyNames(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003886 HandleScope scope;
3887 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003888 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003889 return *GetKeysFor(object);
3890}
3891
3892
3893// Returns either a FixedArray as Runtime_GetPropertyNames,
3894// or, if the given object has an enum cache that contains
3895// all enumerable properties of the object and its prototypes
3896// have none, the map of the object. This is used to speed up
3897// the check for deletions during a for-in.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003898static MaybeObject* Runtime_GetPropertyNamesFast(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003899 ASSERT(args.length() == 1);
3900
3901 CONVERT_CHECKED(JSObject, raw_object, args[0]);
3902
3903 if (raw_object->IsSimpleEnum()) return raw_object->map();
3904
3905 HandleScope scope;
3906 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00003907 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
3908 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003909
3910 // Test again, since cache may have been built by preceding call.
3911 if (object->IsSimpleEnum()) return object->map();
3912
3913 return *content;
3914}
3915
3916
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003917// Find the length of the prototype chain that is to to handled as one. If a
3918// prototype object is hidden it is to be viewed as part of the the object it
3919// is prototype for.
3920static int LocalPrototypeChainLength(JSObject* obj) {
3921 int count = 1;
3922 Object* proto = obj->GetPrototype();
3923 while (proto->IsJSObject() &&
3924 JSObject::cast(proto)->map()->is_hidden_prototype()) {
3925 count++;
3926 proto = JSObject::cast(proto)->GetPrototype();
3927 }
3928 return count;
3929}
3930
3931
3932// Return the names of the local named properties.
3933// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00003934static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003935 HandleScope scope;
3936 ASSERT(args.length() == 1);
3937 if (!args[0]->IsJSObject()) {
3938 return Heap::undefined_value();
3939 }
3940 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3941
3942 // Skip the global proxy as it has no properties and always delegates to the
3943 // real global object.
3944 if (obj->IsJSGlobalProxy()) {
3945 // Only collect names if access is permitted.
3946 if (obj->IsAccessCheckNeeded() &&
3947 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
3948 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
3949 return *Factory::NewJSArray(0);
3950 }
3951 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
3952 }
3953
3954 // Find the number of objects making up this.
3955 int length = LocalPrototypeChainLength(*obj);
3956
3957 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00003958 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003959 int total_property_count = 0;
3960 Handle<JSObject> jsproto = obj;
3961 for (int i = 0; i < length; i++) {
3962 // Only collect names if access is permitted.
3963 if (jsproto->IsAccessCheckNeeded() &&
3964 !Top::MayNamedAccess(*jsproto,
3965 Heap::undefined_value(),
3966 v8::ACCESS_KEYS)) {
3967 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
3968 return *Factory::NewJSArray(0);
3969 }
3970 int n;
3971 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
3972 local_property_count[i] = n;
3973 total_property_count += n;
3974 if (i < length - 1) {
3975 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
3976 }
3977 }
3978
3979 // Allocate an array with storage for all the property names.
3980 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
3981
3982 // Get the property names.
3983 jsproto = obj;
3984 int proto_with_hidden_properties = 0;
3985 for (int i = 0; i < length; i++) {
3986 jsproto->GetLocalPropertyNames(*names,
3987 i == 0 ? 0 : local_property_count[i - 1]);
3988 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
3989 proto_with_hidden_properties++;
3990 }
3991 if (i < length - 1) {
3992 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
3993 }
3994 }
3995
3996 // Filter out name of hidden propeties object.
3997 if (proto_with_hidden_properties > 0) {
3998 Handle<FixedArray> old_names = names;
3999 names = Factory::NewFixedArray(
4000 names->length() - proto_with_hidden_properties);
4001 int dest_pos = 0;
4002 for (int i = 0; i < total_property_count; i++) {
4003 Object* name = old_names->get(i);
4004 if (name == Heap::hidden_symbol()) {
4005 continue;
4006 }
4007 names->set(dest_pos++, name);
4008 }
4009 }
4010
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004011 return *Factory::NewJSArrayWithElements(names);
4012}
4013
4014
4015// Return the names of the local indexed properties.
4016// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004017static MaybeObject* Runtime_GetLocalElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004018 HandleScope scope;
4019 ASSERT(args.length() == 1);
4020 if (!args[0]->IsJSObject()) {
4021 return Heap::undefined_value();
4022 }
4023 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4024
4025 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4026 Handle<FixedArray> names = Factory::NewFixedArray(n);
4027 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4028 return *Factory::NewJSArrayWithElements(names);
4029}
4030
4031
4032// Return information on whether an object has a named or indexed interceptor.
4033// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004034static MaybeObject* Runtime_GetInterceptorInfo(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004035 HandleScope scope;
4036 ASSERT(args.length() == 1);
4037 if (!args[0]->IsJSObject()) {
4038 return Smi::FromInt(0);
4039 }
4040 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4041
4042 int result = 0;
4043 if (obj->HasNamedInterceptor()) result |= 2;
4044 if (obj->HasIndexedInterceptor()) result |= 1;
4045
4046 return Smi::FromInt(result);
4047}
4048
4049
4050// Return property names from named interceptor.
4051// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004052static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004053 HandleScope scope;
4054 ASSERT(args.length() == 1);
4055 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4056
4057 if (obj->HasNamedInterceptor()) {
4058 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4059 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4060 }
4061 return Heap::undefined_value();
4062}
4063
4064
4065// Return element names from indexed interceptor.
4066// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004067static MaybeObject* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004068 HandleScope scope;
4069 ASSERT(args.length() == 1);
4070 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4071
4072 if (obj->HasIndexedInterceptor()) {
4073 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4074 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4075 }
4076 return Heap::undefined_value();
4077}
4078
4079
lrn@chromium.org303ada72010-10-27 09:33:13 +00004080static MaybeObject* Runtime_LocalKeys(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004081 ASSERT_EQ(args.length(), 1);
4082 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4083 HandleScope scope;
4084 Handle<JSObject> object(raw_object);
4085 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4086 LOCAL_ONLY);
4087 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4088 // property array and since the result is mutable we have to create
4089 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004090 int length = contents->length();
4091 Handle<FixedArray> copy = Factory::NewFixedArray(length);
4092 for (int i = 0; i < length; i++) {
4093 Object* entry = contents->get(i);
4094 if (entry->IsString()) {
4095 copy->set(i, entry);
4096 } else {
4097 ASSERT(entry->IsNumber());
4098 HandleScope scope;
4099 Handle<Object> entry_handle(entry);
4100 Handle<Object> entry_str = Factory::NumberToString(entry_handle);
4101 copy->set(i, *entry_str);
4102 }
4103 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004104 return *Factory::NewJSArrayWithElements(copy);
4105}
4106
4107
lrn@chromium.org303ada72010-10-27 09:33:13 +00004108static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109 NoHandleAllocation ha;
4110 ASSERT(args.length() == 1);
4111
4112 // Compute the frame holding the arguments.
4113 JavaScriptFrameIterator it;
4114 it.AdvanceToArgumentsFrame();
4115 JavaScriptFrame* frame = it.frame();
4116
4117 // Get the actual number of provided arguments.
4118 const uint32_t n = frame->GetProvidedParametersCount();
4119
4120 // Try to convert the key to an index. If successful and within
4121 // index return the the argument from the frame.
4122 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004123 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004124 return frame->GetParameter(index);
4125 }
4126
4127 // Convert the key to a string.
4128 HandleScope scope;
4129 bool exception = false;
4130 Handle<Object> converted =
4131 Execution::ToString(args.at<Object>(0), &exception);
4132 if (exception) return Failure::Exception();
4133 Handle<String> key = Handle<String>::cast(converted);
4134
4135 // Try to convert the string key into an array index.
4136 if (key->AsArrayIndex(&index)) {
4137 if (index < n) {
4138 return frame->GetParameter(index);
4139 } else {
4140 return Top::initial_object_prototype()->GetElement(index);
4141 }
4142 }
4143
4144 // Handle special arguments properties.
4145 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
4146 if (key->Equals(Heap::callee_symbol())) return frame->function();
4147
4148 // Lookup in the initial Object.prototype object.
4149 return Top::initial_object_prototype()->GetProperty(*key);
4150}
4151
4152
lrn@chromium.org303ada72010-10-27 09:33:13 +00004153static MaybeObject* Runtime_ToFastProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004154 HandleScope scope;
4155
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004156 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004157 Handle<Object> object = args.at<Object>(0);
4158 if (object->IsJSObject()) {
4159 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004160 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004161 MaybeObject* ok = js_object->TransformToFastProperties(0);
4162 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004163 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004164 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004165 return *object;
4166}
4167
4168
lrn@chromium.org303ada72010-10-27 09:33:13 +00004169static MaybeObject* Runtime_ToSlowProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004170 HandleScope scope;
4171
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004172 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004173 Handle<Object> object = args.at<Object>(0);
4174 if (object->IsJSObject()) {
4175 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004176 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004177 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004178 return *object;
4179}
4180
4181
lrn@chromium.org303ada72010-10-27 09:33:13 +00004182static MaybeObject* Runtime_ToBool(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004183 NoHandleAllocation ha;
4184 ASSERT(args.length() == 1);
4185
4186 return args[0]->ToBoolean();
4187}
4188
4189
4190// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4191// Possible optimizations: put the type string into the oddballs.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004192static MaybeObject* Runtime_Typeof(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004193 NoHandleAllocation ha;
4194
4195 Object* obj = args[0];
4196 if (obj->IsNumber()) return Heap::number_symbol();
4197 HeapObject* heap_obj = HeapObject::cast(obj);
4198
4199 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004200 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004201
4202 InstanceType instance_type = heap_obj->map()->instance_type();
4203 if (instance_type < FIRST_NONSTRING_TYPE) {
4204 return Heap::string_symbol();
4205 }
4206
4207 switch (instance_type) {
4208 case ODDBALL_TYPE:
4209 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
4210 return Heap::boolean_symbol();
4211 }
4212 if (heap_obj->IsNull()) {
4213 return Heap::object_symbol();
4214 }
4215 ASSERT(heap_obj->IsUndefined());
4216 return Heap::undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004217 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004218 return Heap::function_symbol();
4219 default:
4220 // For any kind of object not handled above, the spec rule for
4221 // host objects gives that it is okay to return "object"
4222 return Heap::object_symbol();
4223 }
4224}
4225
4226
lrn@chromium.org25156de2010-04-06 13:10:27 +00004227static bool AreDigits(const char*s, int from, int to) {
4228 for (int i = from; i < to; i++) {
4229 if (s[i] < '0' || s[i] > '9') return false;
4230 }
4231
4232 return true;
4233}
4234
4235
4236static int ParseDecimalInteger(const char*s, int from, int to) {
4237 ASSERT(to - from < 10); // Overflow is not possible.
4238 ASSERT(from < to);
4239 int d = s[from] - '0';
4240
4241 for (int i = from + 1; i < to; i++) {
4242 d = 10 * d + (s[i] - '0');
4243 }
4244
4245 return d;
4246}
4247
4248
lrn@chromium.org303ada72010-10-27 09:33:13 +00004249static MaybeObject* Runtime_StringToNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004250 NoHandleAllocation ha;
4251 ASSERT(args.length() == 1);
4252 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004253 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004254
4255 // Fast case: short integer or some sorts of junk values.
4256 int len = subject->length();
4257 if (subject->IsSeqAsciiString()) {
4258 if (len == 0) return Smi::FromInt(0);
4259
4260 char const* data = SeqAsciiString::cast(subject)->GetChars();
4261 bool minus = (data[0] == '-');
4262 int start_pos = (minus ? 1 : 0);
4263
4264 if (start_pos == len) {
4265 return Heap::nan_value();
4266 } else if (data[start_pos] > '9') {
4267 // Fast check for a junk value. A valid string may start from a
4268 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4269 // the 'I' character ('Infinity'). All of that have codes not greater than
4270 // '9' except 'I'.
4271 if (data[start_pos] != 'I') {
4272 return Heap::nan_value();
4273 }
4274 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4275 // The maximal/minimal smi has 10 digits. If the string has less digits we
4276 // know it will fit into the smi-data type.
4277 int d = ParseDecimalInteger(data, start_pos, len);
4278 if (minus) {
4279 if (d == 0) return Heap::minus_zero_value();
4280 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004281 } else if (!subject->HasHashCode() &&
4282 len <= String::kMaxArrayIndexSize &&
4283 (len == 1 || data[0] != '0')) {
4284 // String hash is not calculated yet but all the data are present.
4285 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004286 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004287#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004288 subject->Hash(); // Force hash calculation.
4289 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4290 static_cast<int>(hash));
4291#endif
4292 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004293 }
4294 return Smi::FromInt(d);
4295 }
4296 }
4297
4298 // Slower case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004299 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
4300}
4301
4302
lrn@chromium.org303ada72010-10-27 09:33:13 +00004303static MaybeObject* Runtime_StringFromCharCodeArray(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004304 NoHandleAllocation ha;
4305 ASSERT(args.length() == 1);
4306
4307 CONVERT_CHECKED(JSArray, codes, args[0]);
4308 int length = Smi::cast(codes->length())->value();
4309
4310 // Check if the string can be ASCII.
4311 int i;
4312 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004313 Object* element;
4314 { MaybeObject* maybe_element = codes->GetElement(i);
4315 // We probably can't get an exception here, but just in order to enforce
4316 // the checking of inputs in the runtime calls we check here.
4317 if (!maybe_element->ToObject(&element)) return maybe_element;
4318 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004319 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4320 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4321 break;
4322 }
4323
lrn@chromium.org303ada72010-10-27 09:33:13 +00004324 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004325 if (i == length) { // The string is ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004326 maybe_object = Heap::AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004327 } else { // The string is not ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004328 maybe_object = Heap::AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004329 }
4330
lrn@chromium.org303ada72010-10-27 09:33:13 +00004331 Object* object = NULL;
4332 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004333 String* result = String::cast(object);
4334 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004335 Object* element;
4336 { MaybeObject* maybe_element = codes->GetElement(i);
4337 if (!maybe_element->ToObject(&element)) return maybe_element;
4338 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004339 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004340 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004341 }
4342 return result;
4343}
4344
4345
4346// kNotEscaped is generated by the following:
4347//
4348// #!/bin/perl
4349// for (my $i = 0; $i < 256; $i++) {
4350// print "\n" if $i % 16 == 0;
4351// my $c = chr($i);
4352// my $escaped = 1;
4353// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4354// print $escaped ? "0, " : "1, ";
4355// }
4356
4357
4358static bool IsNotEscaped(uint16_t character) {
4359 // Only for 8 bit characters, the rest are always escaped (in a different way)
4360 ASSERT(character < 256);
4361 static const char kNotEscaped[256] = {
4362 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4363 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4364 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4365 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4366 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4367 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4368 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4369 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4370 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4371 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4372 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4373 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4374 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4375 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4376 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4377 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4378 };
4379 return kNotEscaped[character] != 0;
4380}
4381
4382
lrn@chromium.org303ada72010-10-27 09:33:13 +00004383static MaybeObject* Runtime_URIEscape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004384 const char hex_chars[] = "0123456789ABCDEF";
4385 NoHandleAllocation ha;
4386 ASSERT(args.length() == 1);
4387 CONVERT_CHECKED(String, source, args[0]);
4388
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004389 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004390
4391 int escaped_length = 0;
4392 int length = source->length();
4393 {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004394 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004395 buffer->Reset(source);
4396 while (buffer->has_more()) {
4397 uint16_t character = buffer->GetNext();
4398 if (character >= 256) {
4399 escaped_length += 6;
4400 } else if (IsNotEscaped(character)) {
4401 escaped_length++;
4402 } else {
4403 escaped_length += 3;
4404 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004405 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004406 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004407 if (escaped_length > String::kMaxLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004408 Top::context()->mark_out_of_memory();
4409 return Failure::OutOfMemoryException();
4410 }
4411 }
4412 }
4413 // No length change implies no change. Return original string if no change.
4414 if (escaped_length == length) {
4415 return source;
4416 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004417 Object* o;
4418 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(escaped_length);
4419 if (!maybe_o->ToObject(&o)) return maybe_o;
4420 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004421 String* destination = String::cast(o);
4422 int dest_position = 0;
4423
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004424 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004425 buffer->Rewind();
4426 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004427 uint16_t chr = buffer->GetNext();
4428 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004429 destination->Set(dest_position, '%');
4430 destination->Set(dest_position+1, 'u');
4431 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4432 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4433 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4434 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004435 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004436 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004437 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004438 dest_position++;
4439 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004440 destination->Set(dest_position, '%');
4441 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4442 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004443 dest_position += 3;
4444 }
4445 }
4446 return destination;
4447}
4448
4449
4450static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4451 static const signed char kHexValue['g'] = {
4452 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4453 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4454 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4455 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4456 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4457 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4458 -1, 10, 11, 12, 13, 14, 15 };
4459
4460 if (character1 > 'f') return -1;
4461 int hi = kHexValue[character1];
4462 if (hi == -1) return -1;
4463 if (character2 > 'f') return -1;
4464 int lo = kHexValue[character2];
4465 if (lo == -1) return -1;
4466 return (hi << 4) + lo;
4467}
4468
4469
ager@chromium.org870a0b62008-11-04 11:43:05 +00004470static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004471 int i,
4472 int length,
4473 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004474 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004475 int32_t hi = 0;
4476 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004477 if (character == '%' &&
4478 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004479 source->Get(i + 1) == 'u' &&
4480 (hi = TwoDigitHex(source->Get(i + 2),
4481 source->Get(i + 3))) != -1 &&
4482 (lo = TwoDigitHex(source->Get(i + 4),
4483 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004484 *step = 6;
4485 return (hi << 8) + lo;
4486 } else if (character == '%' &&
4487 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004488 (lo = TwoDigitHex(source->Get(i + 1),
4489 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004490 *step = 3;
4491 return lo;
4492 } else {
4493 *step = 1;
4494 return character;
4495 }
4496}
4497
4498
lrn@chromium.org303ada72010-10-27 09:33:13 +00004499static MaybeObject* Runtime_URIUnescape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004500 NoHandleAllocation ha;
4501 ASSERT(args.length() == 1);
4502 CONVERT_CHECKED(String, source, args[0]);
4503
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004504 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004505
4506 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004507 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004508
4509 int unescaped_length = 0;
4510 for (int i = 0; i < length; unescaped_length++) {
4511 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004512 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004513 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004514 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004515 i += step;
4516 }
4517
4518 // No length change implies no change. Return original string if no change.
4519 if (unescaped_length == length)
4520 return source;
4521
lrn@chromium.org303ada72010-10-27 09:33:13 +00004522 Object* o;
4523 { MaybeObject* maybe_o = ascii ?
4524 Heap::AllocateRawAsciiString(unescaped_length) :
4525 Heap::AllocateRawTwoByteString(unescaped_length);
4526 if (!maybe_o->ToObject(&o)) return maybe_o;
4527 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004528 String* destination = String::cast(o);
4529
4530 int dest_position = 0;
4531 for (int i = 0; i < length; dest_position++) {
4532 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004533 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004534 i += step;
4535 }
4536 return destination;
4537}
4538
4539
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004540static const unsigned int kQuoteTableLength = 128u;
4541
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004542static const int kJsonQuotesCharactersPerEntry = 8;
4543static const char* const JsonQuotes =
4544 "\\u0000 \\u0001 \\u0002 \\u0003 "
4545 "\\u0004 \\u0005 \\u0006 \\u0007 "
4546 "\\b \\t \\n \\u000b "
4547 "\\f \\r \\u000e \\u000f "
4548 "\\u0010 \\u0011 \\u0012 \\u0013 "
4549 "\\u0014 \\u0015 \\u0016 \\u0017 "
4550 "\\u0018 \\u0019 \\u001a \\u001b "
4551 "\\u001c \\u001d \\u001e \\u001f "
4552 " ! \\\" # "
4553 "$ % & ' "
4554 "( ) * + "
4555 ", - . / "
4556 "0 1 2 3 "
4557 "4 5 6 7 "
4558 "8 9 : ; "
4559 "< = > ? "
4560 "@ A B C "
4561 "D E F G "
4562 "H I J K "
4563 "L M N O "
4564 "P Q R S "
4565 "T U V W "
4566 "X Y Z [ "
4567 "\\\\ ] ^ _ "
4568 "` a b c "
4569 "d e f g "
4570 "h i j k "
4571 "l m n o "
4572 "p q r s "
4573 "t u v w "
4574 "x y z { "
4575 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004576
4577
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004578// For a string that is less than 32k characters it should always be
4579// possible to allocate it in new space.
4580static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4581
4582
4583// Doing JSON quoting cannot make the string more than this many times larger.
4584static const int kJsonQuoteWorstCaseBlowup = 6;
4585
4586
4587// Covers the entire ASCII range (all other characters are unchanged by JSON
4588// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004589static const byte JsonQuoteLengths[kQuoteTableLength] = {
4590 6, 6, 6, 6, 6, 6, 6, 6,
4591 2, 2, 2, 6, 2, 2, 6, 6,
4592 6, 6, 6, 6, 6, 6, 6, 6,
4593 6, 6, 6, 6, 6, 6, 6, 6,
4594 1, 1, 2, 1, 1, 1, 1, 1,
4595 1, 1, 1, 1, 1, 1, 1, 1,
4596 1, 1, 1, 1, 1, 1, 1, 1,
4597 1, 1, 1, 1, 1, 1, 1, 1,
4598 1, 1, 1, 1, 1, 1, 1, 1,
4599 1, 1, 1, 1, 1, 1, 1, 1,
4600 1, 1, 1, 1, 1, 1, 1, 1,
4601 1, 1, 1, 1, 2, 1, 1, 1,
4602 1, 1, 1, 1, 1, 1, 1, 1,
4603 1, 1, 1, 1, 1, 1, 1, 1,
4604 1, 1, 1, 1, 1, 1, 1, 1,
4605 1, 1, 1, 1, 1, 1, 1, 1,
4606};
4607
4608
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004609template <typename StringType>
4610MaybeObject* AllocateRawString(int length);
4611
4612
4613template <>
4614MaybeObject* AllocateRawString<SeqTwoByteString>(int length) {
4615 return Heap::AllocateRawTwoByteString(length);
4616}
4617
4618
4619template <>
4620MaybeObject* AllocateRawString<SeqAsciiString>(int length) {
4621 return Heap::AllocateRawAsciiString(length);
4622}
4623
4624
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004625template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004626static MaybeObject* SlowQuoteJsonString(Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004627 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004628 const Char* read_cursor = characters.start();
4629 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004630 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004631 int quoted_length = kSpaceForQuotes;
4632 while (read_cursor < end) {
4633 Char c = *(read_cursor++);
4634 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4635 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004636 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004637 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004638 }
4639 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004640 MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
4641 Object* new_object;
4642 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004643 return new_alloc;
4644 }
4645 StringType* new_string = StringType::cast(new_object);
4646
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004647 Char* write_cursor = reinterpret_cast<Char*>(
4648 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004649 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004650 *(write_cursor++) = '"';
4651
4652 read_cursor = characters.start();
4653 while (read_cursor < end) {
4654 Char c = *(read_cursor++);
4655 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4656 *(write_cursor++) = c;
4657 } else {
4658 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4659 const char* replacement = JsonQuotes +
4660 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4661 for (int i = 0; i < len; i++) {
4662 *write_cursor++ = *replacement++;
4663 }
4664 }
4665 }
4666 *(write_cursor++) = '"';
4667 return new_string;
4668}
4669
4670
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004671template <typename Char, typename StringType, bool comma>
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004672static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
4673 int length = characters.length();
4674 Counters::quote_json_char_count.Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004675 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004676 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
4677 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004678 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004679 }
4680
4681 MaybeObject* new_alloc = AllocateRawString<StringType>(worst_case_length);
4682 Object* new_object;
4683 if (!new_alloc->ToObject(&new_object)) {
4684 return new_alloc;
4685 }
4686 if (!Heap::new_space()->Contains(new_object)) {
4687 // Even if our string is small enough to fit in new space we still have to
4688 // handle it being allocated in old space as may happen in the third
4689 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
4690 // CEntryStub::GenerateCore.
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004691 return SlowQuoteJsonString<Char, StringType, comma>(characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004692 }
4693 StringType* new_string = StringType::cast(new_object);
4694 ASSERT(Heap::new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004695
4696 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
4697 Char* write_cursor = reinterpret_cast<Char*>(
4698 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004699 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004700 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004701
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004702 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004703 const Char* end = read_cursor + length;
4704 while (read_cursor < end) {
4705 Char c = *(read_cursor++);
4706 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4707 *(write_cursor++) = c;
4708 } else {
4709 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
4710 const char* replacement = JsonQuotes +
4711 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
4712 write_cursor[0] = replacement[0];
4713 if (len > 1) {
4714 write_cursor[1] = replacement[1];
4715 if (len > 2) {
4716 ASSERT(len == 6);
4717 write_cursor[2] = replacement[2];
4718 write_cursor[3] = replacement[3];
4719 write_cursor[4] = replacement[4];
4720 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004721 }
4722 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004723 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004724 }
4725 }
4726 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004727
4728 int final_length = static_cast<int>(
4729 write_cursor - reinterpret_cast<Char*>(
4730 new_string->address() + SeqAsciiString::kHeaderSize));
4731 Heap::new_space()->ShrinkStringAtAllocationBoundary<StringType>(new_string,
4732 final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004733 return new_string;
4734}
4735
4736
4737static MaybeObject* Runtime_QuoteJSONString(Arguments args) {
4738 NoHandleAllocation ha;
4739 CONVERT_CHECKED(String, str, args[0]);
4740 if (!str->IsFlat()) {
4741 MaybeObject* try_flatten = str->TryFlatten();
4742 Object* flat;
4743 if (!try_flatten->ToObject(&flat)) {
4744 return try_flatten;
4745 }
4746 str = String::cast(flat);
4747 ASSERT(str->IsFlat());
4748 }
4749 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004750 return QuoteJsonString<uc16, SeqTwoByteString, false>(str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004751 } else {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004752 return QuoteJsonString<char, SeqAsciiString, false>(str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004753 }
4754}
4755
4756
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00004757static MaybeObject* Runtime_QuoteJSONStringComma(Arguments args) {
4758 NoHandleAllocation ha;
4759 CONVERT_CHECKED(String, str, args[0]);
4760 if (!str->IsFlat()) {
4761 MaybeObject* try_flatten = str->TryFlatten();
4762 Object* flat;
4763 if (!try_flatten->ToObject(&flat)) {
4764 return try_flatten;
4765 }
4766 str = String::cast(flat);
4767 ASSERT(str->IsFlat());
4768 }
4769 if (str->IsTwoByteRepresentation()) {
4770 return QuoteJsonString<uc16, SeqTwoByteString, true>(str->ToUC16Vector());
4771 } else {
4772 return QuoteJsonString<char, SeqAsciiString, true>(str->ToAsciiVector());
4773 }
4774}
4775
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004776
lrn@chromium.org303ada72010-10-27 09:33:13 +00004777static MaybeObject* Runtime_StringParseInt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004778 NoHandleAllocation ha;
4779
4780 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004781 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004782
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004783 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004784
lrn@chromium.org25156de2010-04-06 13:10:27 +00004785 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
4786 double value = StringToInt(s, radix);
4787 return Heap::NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004788}
4789
4790
lrn@chromium.org303ada72010-10-27 09:33:13 +00004791static MaybeObject* Runtime_StringParseFloat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004792 NoHandleAllocation ha;
4793 CONVERT_CHECKED(String, str, args[0]);
4794
4795 // ECMA-262 section 15.1.2.3, empty string is NaN
4796 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
4797
4798 // Create a number object from the value.
4799 return Heap::NumberFromDouble(value);
4800}
4801
4802
4803static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
4804static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
4805
4806
4807template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00004808MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
4809 String* s,
4810 int length,
4811 int input_string_length,
4812 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004813 // We try this twice, once with the assumption that the result is no longer
4814 // than the input and, if that assumption breaks, again with the exact
4815 // length. This may not be pretty, but it is nicer than what was here before
4816 // and I hereby claim my vaffel-is.
4817 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004818 // Allocate the resulting string.
4819 //
4820 // NOTE: This assumes that the upper/lower case of an ascii
4821 // character is also ascii. This is currently the case, but it
4822 // might break in the future if we implement more context and locale
4823 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004824 Object* o;
4825 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
4826 ? Heap::AllocateRawAsciiString(length)
4827 : Heap::AllocateRawTwoByteString(length);
4828 if (!maybe_o->ToObject(&o)) return maybe_o;
4829 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004830 String* result = String::cast(o);
4831 bool has_changed_character = false;
4832
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004833 // Convert all characters to upper case, assuming that they will fit
4834 // in the buffer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004835 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004836 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004837 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004838 // We can assume that the string is not empty
4839 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004840 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004841 bool has_next = buffer->has_more();
4842 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004843 int char_length = mapping->get(current, next, chars);
4844 if (char_length == 0) {
4845 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004846 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004847 i++;
4848 } else if (char_length == 1) {
4849 // Common case: converting the letter resulted in one character.
4850 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004851 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004852 has_changed_character = true;
4853 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004854 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004855 // We've assumed that the result would be as long as the
4856 // input but here is a character that converts to several
4857 // characters. No matter, we calculate the exact length
4858 // of the result and try the whole thing again.
4859 //
4860 // Note that this leaves room for optimization. We could just
4861 // memcpy what we already have to the result string. Also,
4862 // the result string is the last object allocated we could
4863 // "realloc" it and probably, in the vast majority of cases,
4864 // extend the existing string to be able to hold the full
4865 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004866 int next_length = 0;
4867 if (has_next) {
4868 next_length = mapping->get(next, 0, chars);
4869 if (next_length == 0) next_length = 1;
4870 }
4871 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004872 while (buffer->has_more()) {
4873 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004874 // NOTE: we use 0 as the next character here because, while
4875 // the next character may affect what a character converts to,
4876 // it does not in any case affect the length of what it convert
4877 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004878 int char_length = mapping->get(current, 0, chars);
4879 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00004880 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004881 if (current_length > Smi::kMaxValue) {
4882 Top::context()->mark_out_of_memory();
4883 return Failure::OutOfMemoryException();
4884 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004885 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004886 // Try again with the real length.
4887 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004888 } else {
4889 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004890 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004891 i++;
4892 }
4893 has_changed_character = true;
4894 }
4895 current = next;
4896 }
4897 if (has_changed_character) {
4898 return result;
4899 } else {
4900 // If we didn't actually change anything in doing the conversion
4901 // we simple return the result and let the converted string
4902 // become garbage; there is no reason to keep two identical strings
4903 // alive.
4904 return s;
4905 }
4906}
4907
4908
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004909namespace {
4910
lrn@chromium.org303ada72010-10-27 09:33:13 +00004911static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
4912
4913
4914// Given a word and two range boundaries returns a word with high bit
4915// set in every byte iff the corresponding input byte was strictly in
4916// the range (m, n). All the other bits in the result are cleared.
4917// This function is only useful when it can be inlined and the
4918// boundaries are statically known.
4919// Requires: all bytes in the input word and the boundaries must be
4920// ascii (less than 0x7F).
4921static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
4922 // Every byte in an ascii string is less than or equal to 0x7F.
4923 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
4924 // Use strict inequalities since in edge cases the function could be
4925 // further simplified.
4926 ASSERT(0 < m && m < n && n < 0x7F);
4927 // Has high bit set in every w byte less than n.
4928 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
4929 // Has high bit set in every w byte greater than m.
4930 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
4931 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
4932}
4933
4934
4935enum AsciiCaseConversion {
4936 ASCII_TO_LOWER,
4937 ASCII_TO_UPPER
4938};
4939
4940
4941template <AsciiCaseConversion dir>
4942struct FastAsciiConverter {
4943 static bool Convert(char* dst, char* src, int length) {
4944#ifdef DEBUG
4945 char* saved_dst = dst;
4946 char* saved_src = src;
4947#endif
4948 // We rely on the distance between upper and lower case letters
4949 // being a known power of 2.
4950 ASSERT('a' - 'A' == (1 << 5));
4951 // Boundaries for the range of input characters than require conversion.
4952 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
4953 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
4954 bool changed = false;
4955 char* const limit = src + length;
4956#ifdef V8_HOST_CAN_READ_UNALIGNED
4957 // Process the prefix of the input that requires no conversion one
4958 // (machine) word at a time.
4959 while (src <= limit - sizeof(uintptr_t)) {
4960 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
4961 if (AsciiRangeMask(w, lo, hi) != 0) {
4962 changed = true;
4963 break;
4964 }
4965 *reinterpret_cast<uintptr_t*>(dst) = w;
4966 src += sizeof(uintptr_t);
4967 dst += sizeof(uintptr_t);
4968 }
4969 // Process the remainder of the input performing conversion when
4970 // required one word at a time.
4971 while (src <= limit - sizeof(uintptr_t)) {
4972 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
4973 uintptr_t m = AsciiRangeMask(w, lo, hi);
4974 // The mask has high (7th) bit set in every byte that needs
4975 // conversion and we know that the distance between cases is
4976 // 1 << 5.
4977 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
4978 src += sizeof(uintptr_t);
4979 dst += sizeof(uintptr_t);
4980 }
4981#endif
4982 // Process the last few bytes of the input (or the whole input if
4983 // unaligned access is not supported).
4984 while (src < limit) {
4985 char c = *src;
4986 if (lo < c && c < hi) {
4987 c ^= (1 << 5);
4988 changed = true;
4989 }
4990 *dst = c;
4991 ++src;
4992 ++dst;
4993 }
4994#ifdef DEBUG
4995 CheckConvert(saved_dst, saved_src, length, changed);
4996#endif
4997 return changed;
4998 }
4999
5000#ifdef DEBUG
5001 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5002 bool expected_changed = false;
5003 for (int i = 0; i < length; i++) {
5004 if (dst[i] == src[i]) continue;
5005 expected_changed = true;
5006 if (dir == ASCII_TO_LOWER) {
5007 ASSERT('A' <= src[i] && src[i] <= 'Z');
5008 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5009 } else {
5010 ASSERT(dir == ASCII_TO_UPPER);
5011 ASSERT('a' <= src[i] && src[i] <= 'z');
5012 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5013 }
5014 }
5015 ASSERT(expected_changed == changed);
5016 }
5017#endif
5018};
5019
5020
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005021struct ToLowerTraits {
5022 typedef unibrow::ToLowercase UnibrowConverter;
5023
lrn@chromium.org303ada72010-10-27 09:33:13 +00005024 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005025};
5026
5027
5028struct ToUpperTraits {
5029 typedef unibrow::ToUppercase UnibrowConverter;
5030
lrn@chromium.org303ada72010-10-27 09:33:13 +00005031 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005032};
5033
5034} // namespace
5035
5036
5037template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005038MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005039 Arguments args,
5040 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005041 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005042 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005043 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005044
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005045 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005046 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005047 if (length == 0) return s;
5048
5049 // Simpler handling of ascii strings.
5050 //
5051 // NOTE: This assumes that the upper/lower case of an ascii
5052 // character is also ascii. This is currently the case, but it
5053 // might break in the future if we implement more context and locale
5054 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005055 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005056 Object* o;
5057 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(length);
5058 if (!maybe_o->ToObject(&o)) return maybe_o;
5059 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005060 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005061 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005062 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005063 return has_changed_character ? result : s;
5064 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005065
lrn@chromium.org303ada72010-10-27 09:33:13 +00005066 Object* answer;
5067 { MaybeObject* maybe_answer = ConvertCaseHelper(s, length, length, mapping);
5068 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5069 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005070 if (answer->IsSmi()) {
5071 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005072 { MaybeObject* maybe_answer =
5073 ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
5074 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5075 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005076 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005077 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005078}
5079
5080
lrn@chromium.org303ada72010-10-27 09:33:13 +00005081static MaybeObject* Runtime_StringToLowerCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005082 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005083}
5084
5085
lrn@chromium.org303ada72010-10-27 09:33:13 +00005086static MaybeObject* Runtime_StringToUpperCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005087 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005088}
5089
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005090
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005091static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5092 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5093}
5094
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005095
lrn@chromium.org303ada72010-10-27 09:33:13 +00005096static MaybeObject* Runtime_StringTrim(Arguments args) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005097 NoHandleAllocation ha;
5098 ASSERT(args.length() == 3);
5099
5100 CONVERT_CHECKED(String, s, args[0]);
5101 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5102 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5103
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005104 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005105 int length = s->length();
5106
5107 int left = 0;
5108 if (trimLeft) {
5109 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5110 left++;
5111 }
5112 }
5113
5114 int right = length;
5115 if (trimRight) {
5116 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5117 right--;
5118 }
5119 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005120 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005121}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005122
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005123
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005124template <typename SubjectChar, typename PatternChar>
5125void FindStringIndices(Vector<const SubjectChar> subject,
5126 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005127 ZoneList<int>* indices,
5128 unsigned int limit) {
5129 ASSERT(limit > 0);
5130 // Collect indices of pattern in subject, and the end-of-string index.
5131 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005132 StringSearch<PatternChar, SubjectChar> search(pattern);
5133 int pattern_length = pattern.length();
5134 int index = 0;
5135 while (limit > 0) {
5136 index = search.Search(subject, index);
5137 if (index < 0) return;
5138 indices->Add(index);
5139 index += pattern_length;
5140 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005141 }
5142}
5143
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005144
lrn@chromium.org303ada72010-10-27 09:33:13 +00005145static MaybeObject* Runtime_StringSplit(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005146 ASSERT(args.length() == 3);
5147 HandleScope handle_scope;
5148 CONVERT_ARG_CHECKED(String, subject, 0);
5149 CONVERT_ARG_CHECKED(String, pattern, 1);
5150 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5151
5152 int subject_length = subject->length();
5153 int pattern_length = pattern->length();
5154 RUNTIME_ASSERT(pattern_length > 0);
5155
5156 // The limit can be very large (0xffffffffu), but since the pattern
5157 // isn't empty, we can never create more parts than ~half the length
5158 // of the subject.
5159
5160 if (!subject->IsFlat()) FlattenString(subject);
5161
5162 static const int kMaxInitialListCapacity = 16;
5163
5164 ZoneScope scope(DELETE_ON_EXIT);
5165
5166 // Find (up to limit) indices of separator and end-of-string in subject
5167 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5168 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005169 if (!pattern->IsFlat()) FlattenString(pattern);
5170
5171 // No allocation block.
5172 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005173 AssertNoAllocation nogc;
5174 if (subject->IsAsciiRepresentation()) {
5175 Vector<const char> subject_vector = subject->ToAsciiVector();
5176 if (pattern->IsAsciiRepresentation()) {
5177 FindStringIndices(subject_vector,
5178 pattern->ToAsciiVector(),
5179 &indices,
5180 limit);
5181 } else {
5182 FindStringIndices(subject_vector,
5183 pattern->ToUC16Vector(),
5184 &indices,
5185 limit);
5186 }
5187 } else {
5188 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5189 if (pattern->IsAsciiRepresentation()) {
5190 FindStringIndices(subject_vector,
5191 pattern->ToAsciiVector(),
5192 &indices,
5193 limit);
5194 } else {
5195 FindStringIndices(subject_vector,
5196 pattern->ToUC16Vector(),
5197 &indices,
5198 limit);
5199 }
5200 }
5201 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005202
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005203 if (static_cast<uint32_t>(indices.length()) < limit) {
5204 indices.Add(subject_length);
5205 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005206
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005207 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005208
5209 // Create JSArray of substrings separated by separator.
5210 int part_count = indices.length();
5211
5212 Handle<JSArray> result = Factory::NewJSArray(part_count);
5213 result->set_length(Smi::FromInt(part_count));
5214
5215 ASSERT(result->HasFastElements());
5216
5217 if (part_count == 1 && indices.at(0) == subject_length) {
5218 FixedArray::cast(result->elements())->set(0, *subject);
5219 return *result;
5220 }
5221
5222 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5223 int part_start = 0;
5224 for (int i = 0; i < part_count; i++) {
5225 HandleScope local_loop_handle;
5226 int part_end = indices.at(i);
5227 Handle<String> substring =
5228 Factory::NewSubString(subject, part_start, part_end);
5229 elements->set(i, *substring);
5230 part_start = part_end + pattern_length;
5231 }
5232
5233 return *result;
5234}
5235
5236
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005237// Copies ascii characters to the given fixed array looking up
5238// one-char strings in the cache. Gives up on the first char that is
5239// not in the cache and fills the remainder with smi zeros. Returns
5240// the length of the successfully copied prefix.
5241static int CopyCachedAsciiCharsToArray(const char* chars,
5242 FixedArray* elements,
5243 int length) {
5244 AssertNoAllocation nogc;
5245 FixedArray* ascii_cache = Heap::single_character_string_cache();
5246 Object* undefined = Heap::undefined_value();
5247 int i;
5248 for (i = 0; i < length; ++i) {
5249 Object* value = ascii_cache->get(chars[i]);
5250 if (value == undefined) break;
5251 ASSERT(!Heap::InNewSpace(value));
5252 elements->set(i, value, SKIP_WRITE_BARRIER);
5253 }
5254 if (i < length) {
5255 ASSERT(Smi::FromInt(0) == 0);
5256 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5257 }
5258#ifdef DEBUG
5259 for (int j = 0; j < length; ++j) {
5260 Object* element = elements->get(j);
5261 ASSERT(element == Smi::FromInt(0) ||
5262 (element->IsString() && String::cast(element)->LooksValid()));
5263 }
5264#endif
5265 return i;
5266}
5267
5268
5269// Converts a String to JSArray.
5270// For example, "foo" => ["f", "o", "o"].
lrn@chromium.org303ada72010-10-27 09:33:13 +00005271static MaybeObject* Runtime_StringToArray(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005272 HandleScope scope;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005273 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005274 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005275 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005276
5277 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005278 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005279
5280 Handle<FixedArray> elements;
5281 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005282 Object* obj;
5283 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(length);
5284 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5285 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005286 elements = Handle<FixedArray>(FixedArray::cast(obj));
5287
5288 Vector<const char> chars = s->ToAsciiVector();
5289 // Note, this will initialize all elements (not only the prefix)
5290 // to prevent GC from seeing partially initialized array.
5291 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
5292 *elements,
5293 length);
5294
5295 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005296 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5297 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005298 }
5299 } else {
5300 elements = Factory::NewFixedArray(length);
5301 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005302 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5303 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005304 }
5305 }
5306
5307#ifdef DEBUG
5308 for (int i = 0; i < length; ++i) {
5309 ASSERT(String::cast(elements->get(i))->length() == 1);
5310 }
5311#endif
5312
5313 return *Factory::NewJSArrayWithElements(elements);
5314}
5315
5316
lrn@chromium.org303ada72010-10-27 09:33:13 +00005317static MaybeObject* Runtime_NewStringWrapper(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005318 NoHandleAllocation ha;
5319 ASSERT(args.length() == 1);
5320 CONVERT_CHECKED(String, value, args[0]);
5321 return value->ToObject();
5322}
5323
5324
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005325bool Runtime::IsUpperCaseChar(uint16_t ch) {
5326 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
5327 int char_length = to_upper_mapping.get(ch, 0, chars);
5328 return char_length == 0;
5329}
5330
5331
lrn@chromium.org303ada72010-10-27 09:33:13 +00005332static MaybeObject* Runtime_NumberToString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005333 NoHandleAllocation ha;
5334 ASSERT(args.length() == 1);
5335
5336 Object* number = args[0];
5337 RUNTIME_ASSERT(number->IsNumber());
5338
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005339 return Heap::NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005340}
5341
5342
lrn@chromium.org303ada72010-10-27 09:33:13 +00005343static MaybeObject* Runtime_NumberToStringSkipCache(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005344 NoHandleAllocation ha;
5345 ASSERT(args.length() == 1);
5346
5347 Object* number = args[0];
5348 RUNTIME_ASSERT(number->IsNumber());
5349
5350 return Heap::NumberToString(number, false);
5351}
5352
5353
lrn@chromium.org303ada72010-10-27 09:33:13 +00005354static MaybeObject* Runtime_NumberToInteger(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005355 NoHandleAllocation ha;
5356 ASSERT(args.length() == 1);
5357
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005358 CONVERT_DOUBLE_CHECKED(number, args[0]);
5359
5360 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5361 if (number > 0 && number <= Smi::kMaxValue) {
5362 return Smi::FromInt(static_cast<int>(number));
5363 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005364 return Heap::NumberFromDouble(DoubleToInteger(number));
5365}
5366
5367
lrn@chromium.org303ada72010-10-27 09:33:13 +00005368static MaybeObject* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005369 NoHandleAllocation ha;
5370 ASSERT(args.length() == 1);
5371
5372 CONVERT_DOUBLE_CHECKED(number, args[0]);
5373
5374 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5375 if (number > 0 && number <= Smi::kMaxValue) {
5376 return Smi::FromInt(static_cast<int>(number));
5377 }
5378
5379 double double_value = DoubleToInteger(number);
5380 // Map both -0 and +0 to +0.
5381 if (double_value == 0) double_value = 0;
5382
5383 return Heap::NumberFromDouble(double_value);
5384}
5385
5386
lrn@chromium.org303ada72010-10-27 09:33:13 +00005387static MaybeObject* Runtime_NumberToJSUint32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005388 NoHandleAllocation ha;
5389 ASSERT(args.length() == 1);
5390
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005391 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005392 return Heap::NumberFromUint32(number);
5393}
5394
5395
lrn@chromium.org303ada72010-10-27 09:33:13 +00005396static MaybeObject* Runtime_NumberToJSInt32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005397 NoHandleAllocation ha;
5398 ASSERT(args.length() == 1);
5399
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005400 CONVERT_DOUBLE_CHECKED(number, args[0]);
5401
5402 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5403 if (number > 0 && number <= Smi::kMaxValue) {
5404 return Smi::FromInt(static_cast<int>(number));
5405 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005406 return Heap::NumberFromInt32(DoubleToInt32(number));
5407}
5408
5409
ager@chromium.org870a0b62008-11-04 11:43:05 +00005410// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5411// a small integer.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005412static MaybeObject* Runtime_NumberToSmi(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005413 NoHandleAllocation ha;
5414 ASSERT(args.length() == 1);
5415
5416 Object* obj = args[0];
5417 if (obj->IsSmi()) {
5418 return obj;
5419 }
5420 if (obj->IsHeapNumber()) {
5421 double value = HeapNumber::cast(obj)->value();
5422 int int_value = FastD2I(value);
5423 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5424 return Smi::FromInt(int_value);
5425 }
5426 }
5427 return Heap::nan_value();
5428}
5429
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005430
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005431static MaybeObject* Runtime_AllocateHeapNumber(Arguments args) {
5432 NoHandleAllocation ha;
5433 ASSERT(args.length() == 0);
5434 return Heap::AllocateHeapNumber(0);
5435}
5436
5437
lrn@chromium.org303ada72010-10-27 09:33:13 +00005438static MaybeObject* Runtime_NumberAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005439 NoHandleAllocation ha;
5440 ASSERT(args.length() == 2);
5441
5442 CONVERT_DOUBLE_CHECKED(x, args[0]);
5443 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005444 return Heap::NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005445}
5446
5447
lrn@chromium.org303ada72010-10-27 09:33:13 +00005448static MaybeObject* Runtime_NumberSub(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005449 NoHandleAllocation ha;
5450 ASSERT(args.length() == 2);
5451
5452 CONVERT_DOUBLE_CHECKED(x, args[0]);
5453 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005454 return Heap::NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005455}
5456
5457
lrn@chromium.org303ada72010-10-27 09:33:13 +00005458static MaybeObject* Runtime_NumberMul(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005459 NoHandleAllocation ha;
5460 ASSERT(args.length() == 2);
5461
5462 CONVERT_DOUBLE_CHECKED(x, args[0]);
5463 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005464 return Heap::NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005465}
5466
5467
lrn@chromium.org303ada72010-10-27 09:33:13 +00005468static MaybeObject* Runtime_NumberUnaryMinus(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005469 NoHandleAllocation ha;
5470 ASSERT(args.length() == 1);
5471
5472 CONVERT_DOUBLE_CHECKED(x, args[0]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005473 return Heap::NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005474}
5475
5476
lrn@chromium.org303ada72010-10-27 09:33:13 +00005477static MaybeObject* Runtime_NumberAlloc(Arguments args) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005478 NoHandleAllocation ha;
5479 ASSERT(args.length() == 0);
5480
5481 return Heap::NumberFromDouble(9876543210.0);
5482}
5483
5484
lrn@chromium.org303ada72010-10-27 09:33:13 +00005485static MaybeObject* Runtime_NumberDiv(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005486 NoHandleAllocation ha;
5487 ASSERT(args.length() == 2);
5488
5489 CONVERT_DOUBLE_CHECKED(x, args[0]);
5490 CONVERT_DOUBLE_CHECKED(y, args[1]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005491 return Heap::NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005492}
5493
5494
lrn@chromium.org303ada72010-10-27 09:33:13 +00005495static MaybeObject* Runtime_NumberMod(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005496 NoHandleAllocation ha;
5497 ASSERT(args.length() == 2);
5498
5499 CONVERT_DOUBLE_CHECKED(x, args[0]);
5500 CONVERT_DOUBLE_CHECKED(y, args[1]);
5501
ager@chromium.org3811b432009-10-28 14:53:37 +00005502 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005503 // NumberFromDouble may return a Smi instead of a Number object
5504 return Heap::NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005505}
5506
5507
lrn@chromium.org303ada72010-10-27 09:33:13 +00005508static MaybeObject* Runtime_StringAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005509 NoHandleAllocation ha;
5510 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005511 CONVERT_CHECKED(String, str1, args[0]);
5512 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005513 Counters::string_add_runtime.Increment();
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005514 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005515}
5516
5517
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005518template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005519static inline void StringBuilderConcatHelper(String* special,
5520 sinkchar* sink,
5521 FixedArray* fixed_array,
5522 int array_length) {
5523 int position = 0;
5524 for (int i = 0; i < array_length; i++) {
5525 Object* element = fixed_array->get(i);
5526 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005527 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005528 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005529 int pos;
5530 int len;
5531 if (encoded_slice > 0) {
5532 // Position and length encoded in one smi.
5533 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5534 len = StringBuilderSubstringLength::decode(encoded_slice);
5535 } else {
5536 // Position and length encoded in two smis.
5537 Object* obj = fixed_array->get(++i);
5538 ASSERT(obj->IsSmi());
5539 pos = Smi::cast(obj)->value();
5540 len = -encoded_slice;
5541 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005542 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005543 sink + position,
5544 pos,
5545 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005546 position += len;
5547 } else {
5548 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005549 int element_length = string->length();
5550 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005551 position += element_length;
5552 }
5553 }
5554}
5555
5556
lrn@chromium.org303ada72010-10-27 09:33:13 +00005557static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005558 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005559 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005560 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005561 if (!args[1]->IsSmi()) {
5562 Top::context()->mark_out_of_memory();
5563 return Failure::OutOfMemoryException();
5564 }
5565 int array_length = Smi::cast(args[1])->value();
5566 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005567
5568 // This assumption is used by the slice encoding in one or two smis.
5569 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5570
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005571 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005572 if (!array->HasFastElements()) {
5573 return Top::Throw(Heap::illegal_argument_symbol());
5574 }
5575 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005576 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005577 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005578 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005579
5580 if (array_length == 0) {
5581 return Heap::empty_string();
5582 } else if (array_length == 1) {
5583 Object* first = fixed_array->get(0);
5584 if (first->IsString()) return first;
5585 }
5586
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005587 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005588 int position = 0;
5589 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005590 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005591 Object* elt = fixed_array->get(i);
5592 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005593 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005594 int smi_value = Smi::cast(elt)->value();
5595 int pos;
5596 int len;
5597 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005598 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005599 pos = StringBuilderSubstringPosition::decode(smi_value);
5600 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005601 } else {
5602 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005603 len = -smi_value;
5604 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005605 i++;
5606 if (i >= array_length) {
5607 return Top::Throw(Heap::illegal_argument_symbol());
5608 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005609 Object* next_smi = fixed_array->get(i);
5610 if (!next_smi->IsSmi()) {
5611 return Top::Throw(Heap::illegal_argument_symbol());
5612 }
5613 pos = Smi::cast(next_smi)->value();
5614 if (pos < 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005615 return Top::Throw(Heap::illegal_argument_symbol());
5616 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005617 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005618 ASSERT(pos >= 0);
5619 ASSERT(len >= 0);
5620 if (pos > special_length || len > special_length - pos) {
5621 return Top::Throw(Heap::illegal_argument_symbol());
5622 }
5623 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005624 } else if (elt->IsString()) {
5625 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005626 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005627 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005628 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005629 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005630 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005631 } else {
5632 return Top::Throw(Heap::illegal_argument_symbol());
5633 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005634 if (increment > String::kMaxLength - position) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005635 Top::context()->mark_out_of_memory();
5636 return Failure::OutOfMemoryException();
5637 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005638 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005639 }
5640
5641 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005642 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005643
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005644 if (ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005645 { MaybeObject* maybe_object = Heap::AllocateRawAsciiString(length);
5646 if (!maybe_object->ToObject(&object)) return maybe_object;
5647 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005648 SeqAsciiString* answer = SeqAsciiString::cast(object);
5649 StringBuilderConcatHelper(special,
5650 answer->GetChars(),
5651 fixed_array,
5652 array_length);
5653 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005654 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005655 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5656 if (!maybe_object->ToObject(&object)) return maybe_object;
5657 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005658 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5659 StringBuilderConcatHelper(special,
5660 answer->GetChars(),
5661 fixed_array,
5662 array_length);
5663 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005664 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005665}
5666
5667
lrn@chromium.org303ada72010-10-27 09:33:13 +00005668static MaybeObject* Runtime_NumberOr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005669 NoHandleAllocation ha;
5670 ASSERT(args.length() == 2);
5671
5672 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5673 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5674 return Heap::NumberFromInt32(x | y);
5675}
5676
5677
lrn@chromium.org303ada72010-10-27 09:33:13 +00005678static MaybeObject* Runtime_NumberAnd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005679 NoHandleAllocation ha;
5680 ASSERT(args.length() == 2);
5681
5682 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5683 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5684 return Heap::NumberFromInt32(x & y);
5685}
5686
5687
lrn@chromium.org303ada72010-10-27 09:33:13 +00005688static MaybeObject* Runtime_NumberXor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005689 NoHandleAllocation ha;
5690 ASSERT(args.length() == 2);
5691
5692 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5693 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5694 return Heap::NumberFromInt32(x ^ y);
5695}
5696
5697
lrn@chromium.org303ada72010-10-27 09:33:13 +00005698static MaybeObject* Runtime_NumberNot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005699 NoHandleAllocation ha;
5700 ASSERT(args.length() == 1);
5701
5702 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5703 return Heap::NumberFromInt32(~x);
5704}
5705
5706
lrn@chromium.org303ada72010-10-27 09:33:13 +00005707static MaybeObject* Runtime_NumberShl(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005708 NoHandleAllocation ha;
5709 ASSERT(args.length() == 2);
5710
5711 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5712 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5713 return Heap::NumberFromInt32(x << (y & 0x1f));
5714}
5715
5716
lrn@chromium.org303ada72010-10-27 09:33:13 +00005717static MaybeObject* Runtime_NumberShr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005718 NoHandleAllocation ha;
5719 ASSERT(args.length() == 2);
5720
5721 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
5722 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5723 return Heap::NumberFromUint32(x >> (y & 0x1f));
5724}
5725
5726
lrn@chromium.org303ada72010-10-27 09:33:13 +00005727static MaybeObject* Runtime_NumberSar(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005728 NoHandleAllocation ha;
5729 ASSERT(args.length() == 2);
5730
5731 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5732 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5733 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
5734}
5735
5736
lrn@chromium.org303ada72010-10-27 09:33:13 +00005737static MaybeObject* Runtime_NumberEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005738 NoHandleAllocation ha;
5739 ASSERT(args.length() == 2);
5740
5741 CONVERT_DOUBLE_CHECKED(x, args[0]);
5742 CONVERT_DOUBLE_CHECKED(y, args[1]);
5743 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
5744 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
5745 if (x == y) return Smi::FromInt(EQUAL);
5746 Object* result;
5747 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
5748 result = Smi::FromInt(EQUAL);
5749 } else {
5750 result = Smi::FromInt(NOT_EQUAL);
5751 }
5752 return result;
5753}
5754
5755
lrn@chromium.org303ada72010-10-27 09:33:13 +00005756static MaybeObject* Runtime_StringEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005757 NoHandleAllocation ha;
5758 ASSERT(args.length() == 2);
5759
5760 CONVERT_CHECKED(String, x, args[0]);
5761 CONVERT_CHECKED(String, y, args[1]);
5762
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005763 bool not_equal = !x->Equals(y);
5764 // This is slightly convoluted because the value that signifies
5765 // equality is 0 and inequality is 1 so we have to negate the result
5766 // from String::Equals.
5767 ASSERT(not_equal == 0 || not_equal == 1);
5768 STATIC_CHECK(EQUAL == 0);
5769 STATIC_CHECK(NOT_EQUAL == 1);
5770 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005771}
5772
5773
lrn@chromium.org303ada72010-10-27 09:33:13 +00005774static MaybeObject* Runtime_NumberCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005775 NoHandleAllocation ha;
5776 ASSERT(args.length() == 3);
5777
5778 CONVERT_DOUBLE_CHECKED(x, args[0]);
5779 CONVERT_DOUBLE_CHECKED(y, args[1]);
5780 if (isnan(x) || isnan(y)) return args[2];
5781 if (x == y) return Smi::FromInt(EQUAL);
5782 if (isless(x, y)) return Smi::FromInt(LESS);
5783 return Smi::FromInt(GREATER);
5784}
5785
5786
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005787// Compare two Smis as if they were converted to strings and then
5788// compared lexicographically.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005789static MaybeObject* Runtime_SmiLexicographicCompare(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005790 NoHandleAllocation ha;
5791 ASSERT(args.length() == 2);
5792
5793 // Arrays for the individual characters of the two Smis. Smis are
5794 // 31 bit integers and 10 decimal digits are therefore enough.
5795 static int x_elms[10];
5796 static int y_elms[10];
5797
5798 // Extract the integer values from the Smis.
5799 CONVERT_CHECKED(Smi, x, args[0]);
5800 CONVERT_CHECKED(Smi, y, args[1]);
5801 int x_value = x->value();
5802 int y_value = y->value();
5803
5804 // If the integers are equal so are the string representations.
5805 if (x_value == y_value) return Smi::FromInt(EQUAL);
5806
5807 // If one of the integers are zero the normal integer order is the
5808 // same as the lexicographic order of the string representations.
5809 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
5810
ager@chromium.org32912102009-01-16 10:38:43 +00005811 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005812 // smallest because the char code of '-' is less than the char code
5813 // of any digit. Otherwise, we make both values positive.
5814 if (x_value < 0 || y_value < 0) {
5815 if (y_value >= 0) return Smi::FromInt(LESS);
5816 if (x_value >= 0) return Smi::FromInt(GREATER);
5817 x_value = -x_value;
5818 y_value = -y_value;
5819 }
5820
5821 // Convert the integers to arrays of their decimal digits.
5822 int x_index = 0;
5823 int y_index = 0;
5824 while (x_value > 0) {
5825 x_elms[x_index++] = x_value % 10;
5826 x_value /= 10;
5827 }
5828 while (y_value > 0) {
5829 y_elms[y_index++] = y_value % 10;
5830 y_value /= 10;
5831 }
5832
5833 // Loop through the arrays of decimal digits finding the first place
5834 // where they differ.
5835 while (--x_index >= 0 && --y_index >= 0) {
5836 int diff = x_elms[x_index] - y_elms[y_index];
5837 if (diff != 0) return Smi::FromInt(diff);
5838 }
5839
5840 // If one array is a suffix of the other array, the longest array is
5841 // the representation of the largest of the Smis in the
5842 // lexicographic ordering.
5843 return Smi::FromInt(x_index - y_index);
5844}
5845
5846
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005847static Object* StringInputBufferCompare(String* x, String* y) {
5848 static StringInputBuffer bufx;
5849 static StringInputBuffer bufy;
5850 bufx.Reset(x);
5851 bufy.Reset(y);
5852 while (bufx.has_more() && bufy.has_more()) {
5853 int d = bufx.GetNext() - bufy.GetNext();
5854 if (d < 0) return Smi::FromInt(LESS);
5855 else if (d > 0) return Smi::FromInt(GREATER);
5856 }
5857
5858 // x is (non-trivial) prefix of y:
5859 if (bufy.has_more()) return Smi::FromInt(LESS);
5860 // y is prefix of x:
5861 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
5862}
5863
5864
5865static Object* FlatStringCompare(String* x, String* y) {
5866 ASSERT(x->IsFlat());
5867 ASSERT(y->IsFlat());
5868 Object* equal_prefix_result = Smi::FromInt(EQUAL);
5869 int prefix_length = x->length();
5870 if (y->length() < prefix_length) {
5871 prefix_length = y->length();
5872 equal_prefix_result = Smi::FromInt(GREATER);
5873 } else if (y->length() > prefix_length) {
5874 equal_prefix_result = Smi::FromInt(LESS);
5875 }
5876 int r;
5877 if (x->IsAsciiRepresentation()) {
5878 Vector<const char> x_chars = x->ToAsciiVector();
5879 if (y->IsAsciiRepresentation()) {
5880 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005881 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005882 } else {
5883 Vector<const uc16> y_chars = y->ToUC16Vector();
5884 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5885 }
5886 } else {
5887 Vector<const uc16> x_chars = x->ToUC16Vector();
5888 if (y->IsAsciiRepresentation()) {
5889 Vector<const char> y_chars = y->ToAsciiVector();
5890 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5891 } else {
5892 Vector<const uc16> y_chars = y->ToUC16Vector();
5893 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5894 }
5895 }
5896 Object* result;
5897 if (r == 0) {
5898 result = equal_prefix_result;
5899 } else {
5900 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
5901 }
5902 ASSERT(result == StringInputBufferCompare(x, y));
5903 return result;
5904}
5905
5906
lrn@chromium.org303ada72010-10-27 09:33:13 +00005907static MaybeObject* Runtime_StringCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005908 NoHandleAllocation ha;
5909 ASSERT(args.length() == 2);
5910
5911 CONVERT_CHECKED(String, x, args[0]);
5912 CONVERT_CHECKED(String, y, args[1]);
5913
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005914 Counters::string_compare_runtime.Increment();
5915
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005916 // A few fast case tests before we flatten.
5917 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005918 if (y->length() == 0) {
5919 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005920 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005921 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005922 return Smi::FromInt(LESS);
5923 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005924
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005925 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005926 if (d < 0) return Smi::FromInt(LESS);
5927 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005928
lrn@chromium.org303ada72010-10-27 09:33:13 +00005929 Object* obj;
5930 { MaybeObject* maybe_obj = Heap::PrepareForCompare(x);
5931 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5932 }
5933 { MaybeObject* maybe_obj = Heap::PrepareForCompare(y);
5934 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5935 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005936
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005937 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
5938 : StringInputBufferCompare(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005939}
5940
5941
lrn@chromium.org303ada72010-10-27 09:33:13 +00005942static MaybeObject* Runtime_Math_acos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005943 NoHandleAllocation ha;
5944 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005945 Counters::math_acos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005946
5947 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005948 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005949}
5950
5951
lrn@chromium.org303ada72010-10-27 09:33:13 +00005952static MaybeObject* Runtime_Math_asin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005953 NoHandleAllocation ha;
5954 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005955 Counters::math_asin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005956
5957 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005958 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005959}
5960
5961
lrn@chromium.org303ada72010-10-27 09:33:13 +00005962static MaybeObject* Runtime_Math_atan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005963 NoHandleAllocation ha;
5964 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005965 Counters::math_atan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005966
5967 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005968 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005969}
5970
5971
lrn@chromium.org303ada72010-10-27 09:33:13 +00005972static MaybeObject* Runtime_Math_atan2(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005973 NoHandleAllocation ha;
5974 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005975 Counters::math_atan2.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005976
5977 CONVERT_DOUBLE_CHECKED(x, args[0]);
5978 CONVERT_DOUBLE_CHECKED(y, args[1]);
5979 double result;
5980 if (isinf(x) && isinf(y)) {
5981 // Make sure that the result in case of two infinite arguments
5982 // is a multiple of Pi / 4. The sign of the result is determined
5983 // by the first argument (x) and the sign of the second argument
5984 // determines the multiplier: one or three.
5985 static double kPiDividedBy4 = 0.78539816339744830962;
5986 int multiplier = (x < 0) ? -1 : 1;
5987 if (y < 0) multiplier *= 3;
5988 result = multiplier * kPiDividedBy4;
5989 } else {
5990 result = atan2(x, y);
5991 }
5992 return Heap::AllocateHeapNumber(result);
5993}
5994
5995
lrn@chromium.org303ada72010-10-27 09:33:13 +00005996static MaybeObject* Runtime_Math_ceil(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005997 NoHandleAllocation ha;
5998 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005999 Counters::math_ceil.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006000
6001 CONVERT_DOUBLE_CHECKED(x, args[0]);
6002 return Heap::NumberFromDouble(ceiling(x));
6003}
6004
6005
lrn@chromium.org303ada72010-10-27 09:33:13 +00006006static MaybeObject* Runtime_Math_cos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006007 NoHandleAllocation ha;
6008 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006009 Counters::math_cos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006010
6011 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006012 return TranscendentalCache::Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006013}
6014
6015
lrn@chromium.org303ada72010-10-27 09:33:13 +00006016static MaybeObject* Runtime_Math_exp(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006017 NoHandleAllocation ha;
6018 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006019 Counters::math_exp.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006020
6021 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006022 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006023}
6024
6025
lrn@chromium.org303ada72010-10-27 09:33:13 +00006026static MaybeObject* Runtime_Math_floor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006027 NoHandleAllocation ha;
6028 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006029 Counters::math_floor.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006030
6031 CONVERT_DOUBLE_CHECKED(x, args[0]);
6032 return Heap::NumberFromDouble(floor(x));
6033}
6034
6035
lrn@chromium.org303ada72010-10-27 09:33:13 +00006036static MaybeObject* Runtime_Math_log(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006037 NoHandleAllocation ha;
6038 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006039 Counters::math_log.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006040
6041 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006042 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006043}
6044
6045
lrn@chromium.org303ada72010-10-27 09:33:13 +00006046static MaybeObject* Runtime_Math_pow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006047 NoHandleAllocation ha;
6048 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006049 Counters::math_pow.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006050
6051 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006052
6053 // If the second argument is a smi, it is much faster to call the
6054 // custom powi() function than the generic pow().
6055 if (args[1]->IsSmi()) {
6056 int y = Smi::cast(args[1])->value();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006057 return Heap::NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006058 }
6059
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006060 CONVERT_DOUBLE_CHECKED(y, args[1]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006061 return Heap::AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006062}
6063
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006064// Fast version of Math.pow if we know that y is not an integer and
6065// y is not -0.5 or 0.5. Used as slowcase from codegen.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006066static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006067 NoHandleAllocation ha;
6068 ASSERT(args.length() == 2);
6069 CONVERT_DOUBLE_CHECKED(x, args[0]);
6070 CONVERT_DOUBLE_CHECKED(y, args[1]);
6071 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006072 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006073 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006074 return Heap::nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006075 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006076 return Heap::AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006077 }
6078}
6079
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006080
lrn@chromium.org303ada72010-10-27 09:33:13 +00006081static MaybeObject* Runtime_RoundNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006082 NoHandleAllocation ha;
6083 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006084 Counters::math_round.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006085
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006086 if (!args[0]->IsHeapNumber()) {
6087 // Must be smi. Return the argument unchanged for all the other types
6088 // to make fuzz-natives test happy.
6089 return args[0];
6090 }
6091
6092 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6093
6094 double value = number->value();
6095 int exponent = number->get_exponent();
6096 int sign = number->get_sign();
6097
6098 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
6099 // should be rounded to 2^30, which is not smi.
6100 if (!sign && exponent <= kSmiValueSize - 3) {
6101 return Smi::FromInt(static_cast<int>(value + 0.5));
6102 }
6103
6104 // If the magnitude is big enough, there's no place for fraction part. If we
6105 // try to add 0.5 to this number, 1.0 will be added instead.
6106 if (exponent >= 52) {
6107 return number;
6108 }
6109
6110 if (sign && value >= -0.5) return Heap::minus_zero_value();
6111
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006112 // Do not call NumberFromDouble() to avoid extra checks.
6113 return Heap::AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006114}
6115
6116
lrn@chromium.org303ada72010-10-27 09:33:13 +00006117static MaybeObject* Runtime_Math_sin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006118 NoHandleAllocation ha;
6119 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006120 Counters::math_sin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006121
6122 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006123 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006124}
6125
6126
lrn@chromium.org303ada72010-10-27 09:33:13 +00006127static MaybeObject* Runtime_Math_sqrt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006128 NoHandleAllocation ha;
6129 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006130 Counters::math_sqrt.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006131
6132 CONVERT_DOUBLE_CHECKED(x, args[0]);
6133 return Heap::AllocateHeapNumber(sqrt(x));
6134}
6135
6136
lrn@chromium.org303ada72010-10-27 09:33:13 +00006137static MaybeObject* Runtime_Math_tan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006138 NoHandleAllocation ha;
6139 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006140 Counters::math_tan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006141
6142 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006143 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006144}
6145
6146
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006147static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006148 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6149 181, 212, 243, 273, 304, 334};
6150 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6151 182, 213, 244, 274, 305, 335};
6152
6153 year += month / 12;
6154 month %= 12;
6155 if (month < 0) {
6156 year--;
6157 month += 12;
6158 }
6159
6160 ASSERT(month >= 0);
6161 ASSERT(month < 12);
6162
6163 // year_delta is an arbitrary number such that:
6164 // a) year_delta = -1 (mod 400)
6165 // b) year + year_delta > 0 for years in the range defined by
6166 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6167 // Jan 1 1970. This is required so that we don't run into integer
6168 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006169 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006170 // operations.
6171 static const int year_delta = 399999;
6172 static const int base_day = 365 * (1970 + year_delta) +
6173 (1970 + year_delta) / 4 -
6174 (1970 + year_delta) / 100 +
6175 (1970 + year_delta) / 400;
6176
6177 int year1 = year + year_delta;
6178 int day_from_year = 365 * year1 +
6179 year1 / 4 -
6180 year1 / 100 +
6181 year1 / 400 -
6182 base_day;
6183
6184 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006185 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006186 }
6187
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006188 return day_from_year + day_from_month_leap[month] + day - 1;
6189}
6190
6191
lrn@chromium.org303ada72010-10-27 09:33:13 +00006192static MaybeObject* Runtime_DateMakeDay(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006193 NoHandleAllocation ha;
6194 ASSERT(args.length() == 3);
6195
6196 CONVERT_SMI_CHECKED(year, args[0]);
6197 CONVERT_SMI_CHECKED(month, args[1]);
6198 CONVERT_SMI_CHECKED(date, args[2]);
6199
6200 return Smi::FromInt(MakeDay(year, month, date));
6201}
6202
6203
6204static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6205static const int kDaysIn4Years = 4 * 365 + 1;
6206static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6207static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6208static const int kDays1970to2000 = 30 * 365 + 7;
6209static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6210 kDays1970to2000;
6211static const int kYearsOffset = 400000;
6212
6213static const char kDayInYear[] = {
6214 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6215 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6216 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6217 22, 23, 24, 25, 26, 27, 28,
6218 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6219 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6220 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6221 22, 23, 24, 25, 26, 27, 28, 29, 30,
6222 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6223 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6224 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6225 22, 23, 24, 25, 26, 27, 28, 29, 30,
6226 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6227 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6228 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6229 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6230 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6231 22, 23, 24, 25, 26, 27, 28, 29, 30,
6232 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6233 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6234 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6235 22, 23, 24, 25, 26, 27, 28, 29, 30,
6236 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6237 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6238
6239 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6240 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6241 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6242 22, 23, 24, 25, 26, 27, 28,
6243 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6244 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6245 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6246 22, 23, 24, 25, 26, 27, 28, 29, 30,
6247 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6248 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6249 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6250 22, 23, 24, 25, 26, 27, 28, 29, 30,
6251 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6252 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6253 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6254 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6255 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6256 22, 23, 24, 25, 26, 27, 28, 29, 30,
6257 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6258 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6259 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6260 22, 23, 24, 25, 26, 27, 28, 29, 30,
6261 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6262 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6263
6264 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6265 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6266 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6267 22, 23, 24, 25, 26, 27, 28, 29,
6268 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6269 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6270 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6271 22, 23, 24, 25, 26, 27, 28, 29, 30,
6272 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6273 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6274 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6275 22, 23, 24, 25, 26, 27, 28, 29, 30,
6276 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6277 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6278 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6279 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6280 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6281 22, 23, 24, 25, 26, 27, 28, 29, 30,
6282 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6283 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6284 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6285 22, 23, 24, 25, 26, 27, 28, 29, 30,
6286 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6287 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6288
6289 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6290 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6291 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6292 22, 23, 24, 25, 26, 27, 28,
6293 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6294 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6295 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6296 22, 23, 24, 25, 26, 27, 28, 29, 30,
6297 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6298 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6299 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6300 22, 23, 24, 25, 26, 27, 28, 29, 30,
6301 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6302 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6303 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6304 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6305 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6306 22, 23, 24, 25, 26, 27, 28, 29, 30,
6307 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6308 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6309 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6310 22, 23, 24, 25, 26, 27, 28, 29, 30,
6311 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6312 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6313
6314static const char kMonthInYear[] = {
6315 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,
6316 0, 0, 0, 0, 0, 0,
6317 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,
6318 1, 1, 1,
6319 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,
6320 2, 2, 2, 2, 2, 2,
6321 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,
6322 3, 3, 3, 3, 3,
6323 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,
6324 4, 4, 4, 4, 4, 4,
6325 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,
6326 5, 5, 5, 5, 5,
6327 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,
6328 6, 6, 6, 6, 6, 6,
6329 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,
6330 7, 7, 7, 7, 7, 7,
6331 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,
6332 8, 8, 8, 8, 8,
6333 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,
6334 9, 9, 9, 9, 9, 9,
6335 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6336 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6337 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6338 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6339
6340 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,
6341 0, 0, 0, 0, 0, 0,
6342 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,
6343 1, 1, 1,
6344 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,
6345 2, 2, 2, 2, 2, 2,
6346 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,
6347 3, 3, 3, 3, 3,
6348 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,
6349 4, 4, 4, 4, 4, 4,
6350 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,
6351 5, 5, 5, 5, 5,
6352 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,
6353 6, 6, 6, 6, 6, 6,
6354 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,
6355 7, 7, 7, 7, 7, 7,
6356 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,
6357 8, 8, 8, 8, 8,
6358 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,
6359 9, 9, 9, 9, 9, 9,
6360 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6361 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6362 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6363 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6364
6365 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,
6366 0, 0, 0, 0, 0, 0,
6367 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,
6368 1, 1, 1, 1,
6369 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,
6370 2, 2, 2, 2, 2, 2,
6371 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,
6372 3, 3, 3, 3, 3,
6373 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,
6374 4, 4, 4, 4, 4, 4,
6375 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,
6376 5, 5, 5, 5, 5,
6377 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,
6378 6, 6, 6, 6, 6, 6,
6379 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,
6380 7, 7, 7, 7, 7, 7,
6381 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,
6382 8, 8, 8, 8, 8,
6383 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,
6384 9, 9, 9, 9, 9, 9,
6385 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6386 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6387 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6388 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6389
6390 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,
6391 0, 0, 0, 0, 0, 0,
6392 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,
6393 1, 1, 1,
6394 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,
6395 2, 2, 2, 2, 2, 2,
6396 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,
6397 3, 3, 3, 3, 3,
6398 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,
6399 4, 4, 4, 4, 4, 4,
6400 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,
6401 5, 5, 5, 5, 5,
6402 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,
6403 6, 6, 6, 6, 6, 6,
6404 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,
6405 7, 7, 7, 7, 7, 7,
6406 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,
6407 8, 8, 8, 8, 8,
6408 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,
6409 9, 9, 9, 9, 9, 9,
6410 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6411 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6412 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6413 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6414
6415
6416// This function works for dates from 1970 to 2099.
6417static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006418 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006419#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006420 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006421#endif
6422
6423 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6424 date %= kDaysIn4Years;
6425
6426 month = kMonthInYear[date];
6427 day = kDayInYear[date];
6428
6429 ASSERT(MakeDay(year, month, day) == save_date);
6430}
6431
6432
6433static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006434 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006435#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006436 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006437#endif
6438
6439 date += kDaysOffset;
6440 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6441 date %= kDaysIn400Years;
6442
6443 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6444
6445 date--;
6446 int yd1 = date / kDaysIn100Years;
6447 date %= kDaysIn100Years;
6448 year += 100 * yd1;
6449
6450 date++;
6451 int yd2 = date / kDaysIn4Years;
6452 date %= kDaysIn4Years;
6453 year += 4 * yd2;
6454
6455 date--;
6456 int yd3 = date / 365;
6457 date %= 365;
6458 year += yd3;
6459
6460 bool is_leap = (!yd1 || yd2) && !yd3;
6461
6462 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006463 ASSERT(is_leap || (date >= 0));
6464 ASSERT((date < 365) || (is_leap && (date < 366)));
6465 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6466 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6467 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006468
6469 if (is_leap) {
6470 day = kDayInYear[2*365 + 1 + date];
6471 month = kMonthInYear[2*365 + 1 + date];
6472 } else {
6473 day = kDayInYear[date];
6474 month = kMonthInYear[date];
6475 }
6476
6477 ASSERT(MakeDay(year, month, day) == save_date);
6478}
6479
6480
6481static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006482 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006483 if (date >= 0 && date < 32 * kDaysIn4Years) {
6484 DateYMDFromTimeAfter1970(date, year, month, day);
6485 } else {
6486 DateYMDFromTimeSlow(date, year, month, day);
6487 }
6488}
6489
6490
lrn@chromium.org303ada72010-10-27 09:33:13 +00006491static MaybeObject* Runtime_DateYMDFromTime(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006492 NoHandleAllocation ha;
6493 ASSERT(args.length() == 2);
6494
6495 CONVERT_DOUBLE_CHECKED(t, args[0]);
6496 CONVERT_CHECKED(JSArray, res_array, args[1]);
6497
6498 int year, month, day;
6499 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
6500
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006501 RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
6502 FixedArray* elms = FixedArray::cast(res_array->elements());
6503 RUNTIME_ASSERT(elms->length() == 3);
6504
6505 elms->set(0, Smi::FromInt(year));
6506 elms->set(1, Smi::FromInt(month));
6507 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006508
6509 return Heap::undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006510}
6511
6512
lrn@chromium.org303ada72010-10-27 09:33:13 +00006513static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006514 NoHandleAllocation ha;
6515 ASSERT(args.length() == 3);
6516
6517 JSFunction* callee = JSFunction::cast(args[0]);
6518 Object** parameters = reinterpret_cast<Object**>(args[1]);
6519 const int length = Smi::cast(args[2])->value();
6520
lrn@chromium.org303ada72010-10-27 09:33:13 +00006521 Object* result;
6522 { MaybeObject* maybe_result = Heap::AllocateArgumentsObject(callee, length);
6523 if (!maybe_result->ToObject(&result)) return maybe_result;
6524 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006525 // Allocate the elements if needed.
6526 if (length > 0) {
6527 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006528 Object* obj;
6529 { MaybeObject* maybe_obj = Heap::AllocateRawFixedArray(length);
6530 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6531 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006532
6533 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006534 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
6535 array->set_map(Heap::fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006536 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006537
6538 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006539 for (int i = 0; i < length; i++) {
6540 array->set(i, *--parameters, mode);
6541 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006542 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006543 }
6544 return result;
6545}
6546
6547
lrn@chromium.org303ada72010-10-27 09:33:13 +00006548static MaybeObject* Runtime_NewClosure(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006549 HandleScope scope;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006550 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00006551 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006552 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006553 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006554
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006555 // Allocate global closures in old space and allocate local closures
6556 // in new space. Additionally pretenure closures that are assigned
6557 // directly to properties.
6558 pretenure = pretenure || (context->global_context() == *context);
6559 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006560 Handle<JSFunction> result =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006561 Factory::NewFunctionFromSharedFunctionInfo(shared,
6562 context,
6563 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006564 return *result;
6565}
6566
lrn@chromium.org303ada72010-10-27 09:33:13 +00006567static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006568 HandleScope scope;
6569 ASSERT(args.length() == 2);
6570 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6571 CONVERT_ARG_CHECKED(JSArray, params, 1);
6572
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006573 RUNTIME_ASSERT(params->HasFastElements());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006574 FixedArray* fixed = FixedArray::cast(params->elements());
6575
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006576 int fixed_length = Smi::cast(params->length())->value();
6577 SmartPointer<Object**> param_data(NewArray<Object**>(fixed_length));
6578 for (int i = 0; i < fixed_length; i++) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006579 Handle<Object> val = Handle<Object>(fixed->get(i));
6580 param_data[i] = val.location();
6581 }
6582
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006583 bool exception = false;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006584 Handle<Object> result = Execution::New(
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006585 function, fixed_length, *param_data, &exception);
6586 if (exception) {
6587 return Failure::Exception();
6588 }
6589 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006590 return *result;
6591}
6592
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006593
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006594static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
ager@chromium.org5c838252010-02-19 08:53:10 +00006595 Handle<Object> prototype = Factory::null_value();
6596 if (function->has_instance_prototype()) {
6597 prototype = Handle<Object>(function->instance_prototype());
6598 }
6599 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006600 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006601 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006602 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006603 function->shared()->set_construct_stub(
6604 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006605 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006606 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006607}
6608
6609
lrn@chromium.org303ada72010-10-27 09:33:13 +00006610static MaybeObject* Runtime_NewObject(Arguments args) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006611 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006612 ASSERT(args.length() == 1);
6613
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006614 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006615
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006616 // If the constructor isn't a proper function we throw a type error.
6617 if (!constructor->IsJSFunction()) {
6618 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6619 Handle<Object> type_error =
6620 Factory::NewTypeError("not_constructor", arguments);
6621 return Top::Throw(*type_error);
6622 }
6623
6624 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006625
6626 // If function should not have prototype, construction is not allowed. In this
6627 // case generated code bailouts here, since function has no initial_map.
6628 if (!function->should_have_prototype()) {
6629 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6630 Handle<Object> type_error =
6631 Factory::NewTypeError("not_constructor", arguments);
6632 return Top::Throw(*type_error);
6633 }
6634
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006635#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006636 // Handle stepping into constructors if step into is active.
6637 if (Debug::StepInActive()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006638 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006639 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006640#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006641
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006642 if (function->has_initial_map()) {
6643 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006644 // The 'Function' function ignores the receiver object when
6645 // called using 'new' and creates a new JSFunction object that
6646 // is returned. The receiver object is only used for error
6647 // reporting if an error occurs when constructing the new
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006648 // JSFunction. Factory::NewJSObject() should not be used to
6649 // allocate JSFunctions since it does not properly initialize
6650 // the shared part of the function. Since the receiver is
6651 // ignored anyway, we use the global object as the receiver
6652 // instead of a new JSFunction object. This way, errors are
6653 // reported the same way whether or not 'Function' is called
6654 // using 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006655 return Top::context()->global();
6656 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006657 }
6658
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006659 // The function should be compiled for the optimization hints to be
6660 // available. We cannot use EnsureCompiled because that forces a
6661 // compilation through the shared function info which makes it
6662 // impossible for us to optimize.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006663 Handle<SharedFunctionInfo> shared(function->shared());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006664 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006665
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006666 if (!function->has_initial_map() &&
6667 shared->IsInobjectSlackTrackingInProgress()) {
6668 // The tracking is already in progress for another function. We can only
6669 // track one initial_map at a time, so we force the completion before the
6670 // function is called as a constructor for the first time.
6671 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006672 }
6673
6674 bool first_allocation = !shared->live_objects_may_exist();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006675 Handle<JSObject> result = Factory::NewJSObject(function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006676 // Delay setting the stub if inobject slack tracking is in progress.
6677 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
6678 TrySettingInlineConstructStub(function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006679 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006680
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006681 Counters::constructed_objects.Increment();
6682 Counters::constructed_objects_runtime.Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006683
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006684 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006685}
6686
6687
lrn@chromium.org303ada72010-10-27 09:33:13 +00006688static MaybeObject* Runtime_FinalizeInstanceSize(Arguments args) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006689 HandleScope scope;
6690 ASSERT(args.length() == 1);
6691
6692 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6693 function->shared()->CompleteInobjectSlackTracking();
6694 TrySettingInlineConstructStub(function);
6695
6696 return Heap::undefined_value();
6697}
6698
6699
lrn@chromium.org303ada72010-10-27 09:33:13 +00006700static MaybeObject* Runtime_LazyCompile(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006701 HandleScope scope;
6702 ASSERT(args.length() == 1);
6703
6704 Handle<JSFunction> function = args.at<JSFunction>(0);
6705#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00006706 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006707 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006708 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006709 PrintF("]\n");
6710 }
6711#endif
6712
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006713 // Compile the target function. Here we compile using CompileLazyInLoop in
6714 // order to get the optimized version. This helps code like delta-blue
6715 // that calls performance-critical routines through constructors. A
6716 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
6717 // direct call. Since the in-loop tracking takes place through CallICs
6718 // this means that things called through constructors are never known to
6719 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006720 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006721 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006722 return Failure::Exception();
6723 }
6724
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006725 // All done. Return the compiled code.
6726 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006727 return function->code();
6728}
6729
6730
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006731static MaybeObject* Runtime_LazyRecompile(Arguments args) {
6732 HandleScope scope;
6733 ASSERT(args.length() == 1);
6734 Handle<JSFunction> function = args.at<JSFunction>(0);
6735 // If the function is not optimizable or debugger is active continue using the
6736 // code from the full compiler.
6737 if (!function->shared()->code()->optimizable() ||
6738 Debug::has_break_points()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006739 if (FLAG_trace_opt) {
6740 PrintF("[failed to optimize ");
6741 function->PrintName();
6742 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
6743 function->shared()->code()->optimizable() ? "T" : "F",
6744 Debug::has_break_points() ? "T" : "F");
6745 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006746 function->ReplaceCode(function->shared()->code());
6747 return function->code();
6748 }
6749 if (CompileOptimized(function, AstNode::kNoNumber)) {
6750 return function->code();
6751 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006752 if (FLAG_trace_opt) {
6753 PrintF("[failed to optimize ");
6754 function->PrintName();
6755 PrintF(": optimized compilation failed]\n");
6756 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006757 function->ReplaceCode(function->shared()->code());
6758 return Failure::Exception();
6759}
6760
6761
6762static MaybeObject* Runtime_NotifyDeoptimized(Arguments args) {
6763 HandleScope scope;
6764 ASSERT(args.length() == 1);
6765 RUNTIME_ASSERT(args[0]->IsSmi());
6766 Deoptimizer::BailoutType type =
6767 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
6768 Deoptimizer* deoptimizer = Deoptimizer::Grab();
6769 ASSERT(Heap::IsAllocationAllowed());
6770 int frames = deoptimizer->output_count();
6771
6772 JavaScriptFrameIterator it;
6773 JavaScriptFrame* frame = NULL;
6774 for (int i = 0; i < frames; i++) {
6775 if (i != 0) it.Advance();
6776 frame = it.frame();
6777 deoptimizer->InsertHeapNumberValues(frames - i - 1, frame);
6778 }
6779 delete deoptimizer;
6780
6781 RUNTIME_ASSERT(frame->function()->IsJSFunction());
6782 Handle<JSFunction> function(JSFunction::cast(frame->function()));
6783 Handle<Object> arguments;
6784 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00006785 if (frame->GetExpression(i) == Heap::arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006786 if (arguments.is_null()) {
6787 // FunctionGetArguments can't throw an exception, so cast away the
6788 // doubt with an assert.
6789 arguments = Handle<Object>(
6790 Accessors::FunctionGetArguments(*function,
6791 NULL)->ToObjectUnchecked());
6792 ASSERT(*arguments != Heap::null_value());
6793 ASSERT(*arguments != Heap::undefined_value());
6794 }
6795 frame->SetExpression(i, *arguments);
6796 }
6797 }
6798
6799 CompilationCache::MarkForLazyOptimizing(function);
6800 if (type == Deoptimizer::EAGER) {
6801 RUNTIME_ASSERT(function->IsOptimized());
6802 } else {
6803 RUNTIME_ASSERT(!function->IsOptimized());
6804 }
6805
6806 // Avoid doing too much work when running with --always-opt and keep
6807 // the optimized code around.
6808 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
6809 return Heap::undefined_value();
6810 }
6811
6812 // Count the number of optimized activations of the function.
6813 int activations = 0;
6814 while (!it.done()) {
6815 JavaScriptFrame* frame = it.frame();
6816 if (frame->is_optimized() && frame->function() == *function) {
6817 activations++;
6818 }
6819 it.Advance();
6820 }
6821
6822 // TODO(kasperl): For now, we cannot support removing the optimized
6823 // code when we have recursive invocations of the same function.
6824 if (activations == 0) {
6825 if (FLAG_trace_deopt) {
6826 PrintF("[removing optimized code for: ");
6827 function->PrintName();
6828 PrintF("]\n");
6829 }
6830 function->ReplaceCode(function->shared()->code());
6831 }
6832 return Heap::undefined_value();
6833}
6834
6835
6836static MaybeObject* Runtime_NotifyOSR(Arguments args) {
6837 Deoptimizer* deoptimizer = Deoptimizer::Grab();
6838 delete deoptimizer;
6839 return Heap::undefined_value();
6840}
6841
6842
6843static MaybeObject* Runtime_DeoptimizeFunction(Arguments args) {
6844 HandleScope scope;
6845 ASSERT(args.length() == 1);
6846 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6847 if (!function->IsOptimized()) return Heap::undefined_value();
6848
6849 Deoptimizer::DeoptimizeFunction(*function);
6850
6851 return Heap::undefined_value();
6852}
6853
6854
6855static MaybeObject* Runtime_CompileForOnStackReplacement(Arguments args) {
6856 HandleScope scope;
6857 ASSERT(args.length() == 1);
6858 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6859
6860 // We're not prepared to handle a function with arguments object.
6861 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
6862
6863 // We have hit a back edge in an unoptimized frame for a function that was
6864 // selected for on-stack replacement. Find the unoptimized code object.
6865 Handle<Code> unoptimized(function->shared()->code());
6866 // Keep track of whether we've succeeded in optimizing.
6867 bool succeeded = unoptimized->optimizable();
6868 if (succeeded) {
6869 // If we are trying to do OSR when there are already optimized
6870 // activations of the function, it means (a) the function is directly or
6871 // indirectly recursive and (b) an optimized invocation has been
6872 // deoptimized so that we are currently in an unoptimized activation.
6873 // Check for optimized activations of this function.
6874 JavaScriptFrameIterator it;
6875 while (succeeded && !it.done()) {
6876 JavaScriptFrame* frame = it.frame();
6877 succeeded = !frame->is_optimized() || frame->function() != *function;
6878 it.Advance();
6879 }
6880 }
6881
6882 int ast_id = AstNode::kNoNumber;
6883 if (succeeded) {
6884 // The top JS function is this one, the PC is somewhere in the
6885 // unoptimized code.
6886 JavaScriptFrameIterator it;
6887 JavaScriptFrame* frame = it.frame();
6888 ASSERT(frame->function() == *function);
6889 ASSERT(frame->code() == *unoptimized);
6890 ASSERT(unoptimized->contains(frame->pc()));
6891
6892 // Use linear search of the unoptimized code's stack check table to find
6893 // the AST id matching the PC.
6894 Address start = unoptimized->instruction_start();
6895 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
6896 Address table_cursor = start + unoptimized->stack_check_table_start();
6897 uint32_t table_length = Memory::uint32_at(table_cursor);
6898 table_cursor += kIntSize;
6899 for (unsigned i = 0; i < table_length; ++i) {
6900 // Table entries are (AST id, pc offset) pairs.
6901 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
6902 if (pc_offset == target_pc_offset) {
6903 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
6904 break;
6905 }
6906 table_cursor += 2 * kIntSize;
6907 }
6908 ASSERT(ast_id != AstNode::kNoNumber);
6909 if (FLAG_trace_osr) {
6910 PrintF("[replacing on-stack at AST id %d in ", ast_id);
6911 function->PrintName();
6912 PrintF("]\n");
6913 }
6914
6915 // Try to compile the optimized code. A true return value from
6916 // CompileOptimized means that compilation succeeded, not necessarily
6917 // that optimization succeeded.
6918 if (CompileOptimized(function, ast_id) && function->IsOptimized()) {
6919 DeoptimizationInputData* data = DeoptimizationInputData::cast(
6920 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006921 if (data->OsrPcOffset()->value() >= 0) {
6922 if (FLAG_trace_osr) {
6923 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006924 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006925 }
6926 ASSERT(data->OsrAstId()->value() == ast_id);
6927 } else {
6928 // We may never generate the desired OSR entry if we emit an
6929 // early deoptimize.
6930 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006931 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006932 } else {
6933 succeeded = false;
6934 }
6935 }
6936
6937 // Revert to the original stack checks in the original unoptimized code.
6938 if (FLAG_trace_osr) {
6939 PrintF("[restoring original stack checks in ");
6940 function->PrintName();
6941 PrintF("]\n");
6942 }
6943 StackCheckStub check_stub;
6944 Handle<Code> check_code = check_stub.GetCode();
6945 Handle<Code> replacement_code(
6946 Builtins::builtin(Builtins::OnStackReplacement));
ager@chromium.org0ee099b2011-01-25 14:06:47 +00006947 Deoptimizer::RevertStackCheckCode(*unoptimized,
6948 *check_code,
6949 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006950
6951 // Allow OSR only at nesting level zero again.
6952 unoptimized->set_allow_osr_at_loop_nesting_level(0);
6953
6954 // If the optimization attempt succeeded, return the AST id tagged as a
6955 // smi. This tells the builtin that we need to translate the unoptimized
6956 // frame to an optimized one.
6957 if (succeeded) {
6958 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
6959 return Smi::FromInt(ast_id);
6960 } else {
6961 return Smi::FromInt(-1);
6962 }
6963}
6964
6965
lrn@chromium.org303ada72010-10-27 09:33:13 +00006966static MaybeObject* Runtime_GetFunctionDelegate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006967 HandleScope scope;
6968 ASSERT(args.length() == 1);
6969 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6970 return *Execution::GetFunctionDelegate(args.at<Object>(0));
6971}
6972
6973
lrn@chromium.org303ada72010-10-27 09:33:13 +00006974static MaybeObject* Runtime_GetConstructorDelegate(Arguments args) {
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006975 HandleScope scope;
6976 ASSERT(args.length() == 1);
6977 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6978 return *Execution::GetConstructorDelegate(args.at<Object>(0));
6979}
6980
6981
lrn@chromium.org303ada72010-10-27 09:33:13 +00006982static MaybeObject* Runtime_NewContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006983 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00006984 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006985
kasper.lund7276f142008-07-30 08:49:36 +00006986 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00006987 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00006988 Object* result;
6989 { MaybeObject* maybe_result = Heap::AllocateFunctionContext(length, function);
6990 if (!maybe_result->ToObject(&result)) return maybe_result;
6991 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006992
6993 Top::set_context(Context::cast(result));
6994
kasper.lund7276f142008-07-30 08:49:36 +00006995 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006996}
6997
lrn@chromium.org303ada72010-10-27 09:33:13 +00006998
6999MUST_USE_RESULT static MaybeObject* PushContextHelper(Object* object,
7000 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007001 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007002 Object* js_object = object;
7003 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007004 MaybeObject* maybe_js_object = js_object->ToObject();
7005 if (!maybe_js_object->ToObject(&js_object)) {
7006 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7007 return maybe_js_object;
7008 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007009 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007010 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007011 Handle<Object> result =
7012 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
7013 return Top::Throw(*result);
7014 }
7015 }
7016
lrn@chromium.org303ada72010-10-27 09:33:13 +00007017 Object* result;
7018 { MaybeObject* maybe_result =
7019 Heap::AllocateWithContext(Top::context(),
7020 JSObject::cast(js_object),
7021 is_catch_context);
7022 if (!maybe_result->ToObject(&result)) return maybe_result;
7023 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007024
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007025 Context* context = Context::cast(result);
7026 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007027
kasper.lund7276f142008-07-30 08:49:36 +00007028 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007029}
7030
7031
lrn@chromium.org303ada72010-10-27 09:33:13 +00007032static MaybeObject* Runtime_PushContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007033 NoHandleAllocation ha;
7034 ASSERT(args.length() == 1);
7035 return PushContextHelper(args[0], false);
7036}
7037
7038
lrn@chromium.org303ada72010-10-27 09:33:13 +00007039static MaybeObject* Runtime_PushCatchContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007040 NoHandleAllocation ha;
7041 ASSERT(args.length() == 1);
7042 return PushContextHelper(args[0], true);
7043}
7044
7045
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007046static MaybeObject* Runtime_DeleteContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007047 HandleScope scope;
7048 ASSERT(args.length() == 2);
7049
7050 CONVERT_ARG_CHECKED(Context, context, 0);
7051 CONVERT_ARG_CHECKED(String, name, 1);
7052
7053 int index;
7054 PropertyAttributes attributes;
7055 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007056 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007057
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007058 // If the slot was not found the result is true.
7059 if (holder.is_null()) {
7060 return Heap::true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007061 }
7062
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007063 // If the slot was found in a context, it should be DONT_DELETE.
7064 if (holder->IsContext()) {
7065 return Heap::false_value();
7066 }
7067
7068 // The slot was found in a JSObject, either a context extension object,
7069 // the global object, or an arguments object. Try to delete it
7070 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7071 // which allows deleting all parameters in functions that mention
7072 // 'arguments', we do this even for the case of slots found on an
7073 // arguments object. The slot was found on an arguments object if the
7074 // index is non-negative.
7075 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7076 if (index >= 0) {
7077 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7078 } else {
7079 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7080 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007081}
7082
7083
ager@chromium.orga1645e22009-09-09 19:27:10 +00007084// A mechanism to return a pair of Object pointers in registers (if possible).
7085// How this is achieved is calling convention-dependent.
7086// All currently supported x86 compiles uses calling conventions that are cdecl
7087// variants where a 64-bit value is returned in two 32-bit registers
7088// (edx:eax on ia32, r1:r0 on ARM).
7089// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7090// In Win64 calling convention, a struct of two pointers is returned in memory,
7091// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007092#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007093struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007094 MaybeObject* x;
7095 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007096};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007097
lrn@chromium.org303ada72010-10-27 09:33:13 +00007098static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007099 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007100 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7101 // In Win64 they are assigned to a hidden first argument.
7102 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007103}
7104#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007105typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007106static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007107 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007108 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007109}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007110#endif
7111
7112
lrn@chromium.org303ada72010-10-27 09:33:13 +00007113static inline MaybeObject* Unhole(MaybeObject* x,
7114 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007115 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7116 USE(attributes);
7117 return x->IsTheHole() ? Heap::undefined_value() : x;
7118}
7119
7120
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007121static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
7122 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007123 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007124 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007125 JSFunction* context_extension_function =
7126 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007127 // If the holder isn't a context extension object, we just return it
7128 // as the receiver. This allows arguments objects to be used as
7129 // receivers, but only if they are put in the context scope chain
7130 // explicitly via a with-statement.
7131 Object* constructor = holder->map()->constructor();
7132 if (constructor != context_extension_function) return holder;
7133 // Fall back to using the global object as the receiver if the
7134 // property turns out to be a local variable allocated in a context
7135 // extension object - introduced via eval.
7136 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007137}
7138
7139
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007140static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007141 HandleScope scope;
ager@chromium.orga1645e22009-09-09 19:27:10 +00007142 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007143
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007144 if (!args[0]->IsContext() || !args[1]->IsString()) {
ager@chromium.org3e875802009-06-29 08:26:34 +00007145 return MakePair(Top::ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007146 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007147 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007148 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007149
7150 int index;
7151 PropertyAttributes attributes;
7152 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007153 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007154
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007155 // If the index is non-negative, the slot has been found in a local
7156 // variable or a parameter. Read it from the context object or the
7157 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007158 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007159 // If the "property" we were looking for is a local variable or an
7160 // argument in a context, the receiver is the global object; see
7161 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
7162 JSObject* receiver = Top::context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007163 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007164 ? Context::cast(*holder)->get(index)
7165 : JSObject::cast(*holder)->GetElement(index);
7166 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007167 }
7168
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007169 // If the holder is found, we read the property from it.
7170 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007171 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007172 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007173 JSObject* receiver;
7174 if (object->IsGlobalObject()) {
7175 receiver = GlobalObject::cast(object)->global_receiver();
7176 } else if (context->is_exception_holder(*holder)) {
7177 receiver = Top::context()->global()->global_receiver();
7178 } else {
7179 receiver = ComputeReceiverForNonGlobal(object);
7180 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007181 // No need to unhole the value here. This is taken care of by the
7182 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007183 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007184 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007185 }
7186
7187 if (throw_error) {
7188 // The property doesn't exist - throw exception.
7189 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007190 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007191 return MakePair(Top::Throw(*reference_error), NULL);
7192 } else {
7193 // The property doesn't exist - return undefined
7194 return MakePair(Heap::undefined_value(), Heap::undefined_value());
7195 }
7196}
7197
7198
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007199static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007200 return LoadContextSlotHelper(args, true);
7201}
7202
7203
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007204static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007205 return LoadContextSlotHelper(args, false);
7206}
7207
7208
lrn@chromium.org303ada72010-10-27 09:33:13 +00007209static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007210 HandleScope scope;
7211 ASSERT(args.length() == 3);
7212
7213 Handle<Object> value(args[0]);
7214 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007215 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007216
7217 int index;
7218 PropertyAttributes attributes;
7219 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007220 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007221
7222 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007223 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007224 // Ignore if read_only variable.
7225 if ((attributes & READ_ONLY) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007226 Handle<Context>::cast(holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007227 }
7228 } else {
7229 ASSERT((attributes & READ_ONLY) == 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007230 Handle<JSObject>::cast(holder)->SetElement(index, *value)->
7231 ToObjectUnchecked();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007232 }
7233 return *value;
7234 }
7235
7236 // Slow case: The property is not in a FixedArray context.
7237 // It is either in an JSObject extension context or it was not found.
7238 Handle<JSObject> context_ext;
7239
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007240 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007241 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007242 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007243 } else {
7244 // The property was not found. It needs to be stored in the global context.
7245 ASSERT(attributes == ABSENT);
7246 attributes = NONE;
7247 context_ext = Handle<JSObject>(Top::context()->global());
7248 }
7249
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007250 // Set the property, but ignore if read_only variable on the context
7251 // extension object itself.
7252 if ((attributes & READ_ONLY) == 0 ||
7253 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00007254 Handle<Object> set = SetProperty(context_ext, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007255 if (set.is_null()) {
7256 // Failure::Exception is converted to a null handle in the
7257 // handle-based methods such as SetProperty. We therefore need
7258 // to convert null handles back to exceptions.
7259 ASSERT(Top::has_pending_exception());
7260 return Failure::Exception();
7261 }
7262 }
7263 return *value;
7264}
7265
7266
lrn@chromium.org303ada72010-10-27 09:33:13 +00007267static MaybeObject* Runtime_Throw(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007268 HandleScope scope;
7269 ASSERT(args.length() == 1);
7270
7271 return Top::Throw(args[0]);
7272}
7273
7274
lrn@chromium.org303ada72010-10-27 09:33:13 +00007275static MaybeObject* Runtime_ReThrow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007276 HandleScope scope;
7277 ASSERT(args.length() == 1);
7278
7279 return Top::ReThrow(args[0]);
7280}
7281
7282
lrn@chromium.org303ada72010-10-27 09:33:13 +00007283static MaybeObject* Runtime_PromoteScheduledException(Arguments args) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007284 ASSERT_EQ(0, args.length());
7285 return Top::PromoteScheduledException();
7286}
7287
7288
lrn@chromium.org303ada72010-10-27 09:33:13 +00007289static MaybeObject* Runtime_ThrowReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007290 HandleScope scope;
7291 ASSERT(args.length() == 1);
7292
7293 Handle<Object> name(args[0]);
7294 Handle<Object> reference_error =
7295 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
7296 return Top::Throw(*reference_error);
7297}
7298
7299
lrn@chromium.org303ada72010-10-27 09:33:13 +00007300static MaybeObject* Runtime_StackOverflow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007301 NoHandleAllocation na;
7302 return Top::StackOverflow();
7303}
7304
7305
lrn@chromium.org303ada72010-10-27 09:33:13 +00007306static MaybeObject* Runtime_StackGuard(Arguments args) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007307 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007308
7309 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007310 if (StackGuard::IsStackOverflow()) {
7311 return Runtime_StackOverflow(args);
7312 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007313
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007314 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007315}
7316
7317
7318// NOTE: These PrintXXX functions are defined for all builds (not just
7319// DEBUG builds) because we may want to be able to trace function
7320// calls in all modes.
7321static void PrintString(String* str) {
7322 // not uncommon to have empty strings
7323 if (str->length() > 0) {
7324 SmartPointer<char> s =
7325 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
7326 PrintF("%s", *s);
7327 }
7328}
7329
7330
7331static void PrintObject(Object* obj) {
7332 if (obj->IsSmi()) {
7333 PrintF("%d", Smi::cast(obj)->value());
7334 } else if (obj->IsString() || obj->IsSymbol()) {
7335 PrintString(String::cast(obj));
7336 } else if (obj->IsNumber()) {
7337 PrintF("%g", obj->Number());
7338 } else if (obj->IsFailure()) {
7339 PrintF("<failure>");
7340 } else if (obj->IsUndefined()) {
7341 PrintF("<undefined>");
7342 } else if (obj->IsNull()) {
7343 PrintF("<null>");
7344 } else if (obj->IsTrue()) {
7345 PrintF("<true>");
7346 } else if (obj->IsFalse()) {
7347 PrintF("<false>");
7348 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007349 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007350 }
7351}
7352
7353
7354static int StackSize() {
7355 int n = 0;
7356 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
7357 return n;
7358}
7359
7360
7361static void PrintTransition(Object* result) {
7362 // indentation
7363 { const int nmax = 80;
7364 int n = StackSize();
7365 if (n <= nmax)
7366 PrintF("%4d:%*s", n, n, "");
7367 else
7368 PrintF("%4d:%*s", n, nmax, "...");
7369 }
7370
7371 if (result == NULL) {
7372 // constructor calls
7373 JavaScriptFrameIterator it;
7374 JavaScriptFrame* frame = it.frame();
7375 if (frame->IsConstructor()) PrintF("new ");
7376 // function name
7377 Object* fun = frame->function();
7378 if (fun->IsJSFunction()) {
7379 PrintObject(JSFunction::cast(fun)->shared()->name());
7380 } else {
7381 PrintObject(fun);
7382 }
7383 // function arguments
7384 // (we are intentionally only printing the actually
7385 // supplied parameters, not all parameters required)
7386 PrintF("(this=");
7387 PrintObject(frame->receiver());
7388 const int length = frame->GetProvidedParametersCount();
7389 for (int i = 0; i < length; i++) {
7390 PrintF(", ");
7391 PrintObject(frame->GetParameter(i));
7392 }
7393 PrintF(") {\n");
7394
7395 } else {
7396 // function result
7397 PrintF("} -> ");
7398 PrintObject(result);
7399 PrintF("\n");
7400 }
7401}
7402
7403
lrn@chromium.org303ada72010-10-27 09:33:13 +00007404static MaybeObject* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007405 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007406 NoHandleAllocation ha;
7407 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007408 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007409}
7410
7411
lrn@chromium.org303ada72010-10-27 09:33:13 +00007412static MaybeObject* Runtime_TraceExit(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007413 NoHandleAllocation ha;
7414 PrintTransition(args[0]);
7415 return args[0]; // return TOS
7416}
7417
7418
lrn@chromium.org303ada72010-10-27 09:33:13 +00007419static MaybeObject* Runtime_DebugPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007420 NoHandleAllocation ha;
7421 ASSERT(args.length() == 1);
7422
7423#ifdef DEBUG
7424 if (args[0]->IsString()) {
7425 // If we have a string, assume it's a code "marker"
7426 // and print some interesting cpu debugging info.
7427 JavaScriptFrameIterator it;
7428 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007429 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
7430 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007431 } else {
7432 PrintF("DebugPrint: ");
7433 }
7434 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007435 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007436 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007437 HeapObject::cast(args[0])->map()->Print();
7438 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007439#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007440 // ShortPrint is available in release mode. Print is not.
7441 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007442#endif
7443 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00007444 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007445
7446 return args[0]; // return TOS
7447}
7448
7449
lrn@chromium.org303ada72010-10-27 09:33:13 +00007450static MaybeObject* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007451 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007452 NoHandleAllocation ha;
7453 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007454 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007455}
7456
7457
lrn@chromium.org303ada72010-10-27 09:33:13 +00007458static MaybeObject* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007459 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007460 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007461
7462 // According to ECMA-262, section 15.9.1, page 117, the precision of
7463 // the number in a Date object representing a particular instant in
7464 // time is milliseconds. Therefore, we floor the result of getting
7465 // the OS time.
7466 double millis = floor(OS::TimeCurrentMillis());
7467 return Heap::NumberFromDouble(millis);
7468}
7469
7470
lrn@chromium.org303ada72010-10-27 09:33:13 +00007471static MaybeObject* Runtime_DateParseString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007472 HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007473 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007474
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007475 CONVERT_ARG_CHECKED(String, str, 0);
7476 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007477
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007478 CONVERT_ARG_CHECKED(JSArray, output, 1);
7479 RUNTIME_ASSERT(output->HasFastElements());
7480
7481 AssertNoAllocation no_allocation;
7482
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007483 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007484 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
7485 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007486 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007487 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007488 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007489 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007490 result = DateParser::Parse(str->ToUC16Vector(), output_array);
7491 }
7492
7493 if (result) {
7494 return *output;
7495 } else {
7496 return Heap::null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007497 }
7498}
7499
7500
lrn@chromium.org303ada72010-10-27 09:33:13 +00007501static MaybeObject* Runtime_DateLocalTimezone(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007502 NoHandleAllocation ha;
7503 ASSERT(args.length() == 1);
7504
7505 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00007506 const char* zone = OS::LocalTimezone(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007507 return Heap::AllocateStringFromUtf8(CStrVector(zone));
7508}
7509
7510
lrn@chromium.org303ada72010-10-27 09:33:13 +00007511static MaybeObject* Runtime_DateLocalTimeOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007512 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007513 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007514
7515 return Heap::NumberFromDouble(OS::LocalTimeOffset());
7516}
7517
7518
lrn@chromium.org303ada72010-10-27 09:33:13 +00007519static MaybeObject* Runtime_DateDaylightSavingsOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007520 NoHandleAllocation ha;
7521 ASSERT(args.length() == 1);
7522
7523 CONVERT_DOUBLE_CHECKED(x, args[0]);
7524 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
7525}
7526
7527
lrn@chromium.org303ada72010-10-27 09:33:13 +00007528static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007529 ASSERT(args.length() == 1);
7530 Object* global = args[0];
7531 if (!global->IsJSGlobalObject()) return Heap::null_value();
7532 return JSGlobalObject::cast(global)->global_receiver();
7533}
7534
7535
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007536static MaybeObject* Runtime_ParseJson(Arguments args) {
7537 HandleScope scope;
7538 ASSERT_EQ(1, args.length());
7539 CONVERT_ARG_CHECKED(String, source, 0);
7540
7541 Handle<Object> result = JsonParser::Parse(source);
7542 if (result.is_null()) {
7543 // Syntax error or stack overflow in scanner.
7544 ASSERT(Top::has_pending_exception());
7545 return Failure::Exception();
7546 }
7547 return *result;
7548}
7549
7550
lrn@chromium.org303ada72010-10-27 09:33:13 +00007551static MaybeObject* Runtime_CompileString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007552 HandleScope scope;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007553 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007554 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007555
ager@chromium.org381abbb2009-02-25 13:23:22 +00007556 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007557 Handle<Context> context(Top::context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007558 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
7559 context,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007560 true);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007561 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007562 Handle<JSFunction> fun =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007563 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007564 return *fun;
7565}
7566
7567
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007568static ObjectPair CompileGlobalEval(Handle<String> source,
7569 Handle<Object> receiver) {
7570 // Deal with a normal eval call with a string argument. Compile it
7571 // and return the compiled function bound in the local context.
7572 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
7573 source,
7574 Handle<Context>(Top::context()),
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007575 Top::context()->IsGlobalContext());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007576 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
7577 Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
7578 shared,
7579 Handle<Context>(Top::context()),
7580 NOT_TENURED);
7581 return MakePair(*compiled, *receiver);
7582}
7583
7584
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007585static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
7586 ASSERT(args.length() == 3);
7587 if (!args[0]->IsJSFunction()) {
7588 return MakePair(Top::ThrowIllegalOperation(), NULL);
7589 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007590
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007591 HandleScope scope;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007592 Handle<JSFunction> callee = args.at<JSFunction>(0);
7593 Handle<Object> receiver; // Will be overwritten.
7594
7595 // Compute the calling context.
7596 Handle<Context> context = Handle<Context>(Top::context());
7597#ifdef DEBUG
7598 // Make sure Top::context() agrees with the old code that traversed
7599 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007600 StackFrameLocator locator;
7601 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007602 ASSERT(Context::cast(frame->context()) == *context);
7603#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007604
7605 // Find where the 'eval' symbol is bound. It is unaliased only if
7606 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007607 int index = -1;
7608 PropertyAttributes attributes = ABSENT;
7609 while (true) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007610 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
7611 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007612 // Stop search when eval is found or when the global context is
7613 // reached.
7614 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007615 if (context->is_function_context()) {
7616 context = Handle<Context>(Context::cast(context->closure()->context()));
7617 } else {
7618 context = Handle<Context>(context->previous());
7619 }
7620 }
7621
iposva@chromium.org245aa852009-02-10 00:49:54 +00007622 // If eval could not be resolved, it has been deleted and we need to
7623 // throw a reference error.
7624 if (attributes == ABSENT) {
7625 Handle<Object> name = Factory::eval_symbol();
7626 Handle<Object> reference_error =
7627 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007628 return MakePair(Top::Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007629 }
7630
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007631 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007632 // 'eval' is not bound in the global context. Just call the function
7633 // with the given arguments. This is not necessarily the global eval.
7634 if (receiver->IsContext()) {
7635 context = Handle<Context>::cast(receiver);
7636 receiver = Handle<Object>(context->get(index));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007637 } else if (receiver->IsJSContextExtensionObject()) {
7638 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007639 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007640 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007641 }
7642
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007643 // 'eval' is bound in the global context, but it may have been overwritten.
7644 // Compare it to the builtin 'GlobalEval' function to make sure.
7645 if (*callee != Top::global_context()->global_eval_fun() ||
7646 !args[1]->IsString()) {
7647 return MakePair(*callee, Top::context()->global()->global_receiver());
7648 }
7649
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007650 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
7651}
7652
7653
7654static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
7655 ASSERT(args.length() == 3);
7656 if (!args[0]->IsJSFunction()) {
7657 return MakePair(Top::ThrowIllegalOperation(), NULL);
7658 }
7659
7660 HandleScope scope;
7661 Handle<JSFunction> callee = args.at<JSFunction>(0);
7662
7663 // 'eval' is bound in the global context, but it may have been overwritten.
7664 // Compare it to the builtin 'GlobalEval' function to make sure.
7665 if (*callee != Top::global_context()->global_eval_fun() ||
7666 !args[1]->IsString()) {
7667 return MakePair(*callee, Top::context()->global()->global_receiver());
7668 }
7669
7670 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007671}
7672
7673
lrn@chromium.org303ada72010-10-27 09:33:13 +00007674static MaybeObject* Runtime_SetNewFunctionAttributes(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007675 // This utility adjusts the property attributes for newly created Function
7676 // object ("new Function(...)") by changing the map.
7677 // All it does is changing the prototype property to enumerable
7678 // as specified in ECMA262, 15.3.5.2.
7679 HandleScope scope;
7680 ASSERT(args.length() == 1);
7681 CONVERT_ARG_CHECKED(JSFunction, func, 0);
7682 ASSERT(func->map()->instance_type() ==
7683 Top::function_instance_map()->instance_type());
7684 ASSERT(func->map()->instance_size() ==
7685 Top::function_instance_map()->instance_size());
7686 func->set_map(*Top::function_instance_map());
7687 return *func;
7688}
7689
7690
lrn@chromium.org303ada72010-10-27 09:33:13 +00007691static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007692 // Allocate a block of memory in NewSpace (filled with a filler).
7693 // Use as fallback for allocation in generated code when NewSpace
7694 // is full.
7695 ASSERT(args.length() == 1);
7696 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
7697 int size = size_smi->value();
7698 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
7699 RUNTIME_ASSERT(size > 0);
7700 static const int kMinFreeNewSpaceAfterGC =
7701 Heap::InitialSemiSpaceSize() * 3/4;
7702 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007703 Object* allocation;
7704 { MaybeObject* maybe_allocation = Heap::new_space()->AllocateRaw(size);
7705 if (maybe_allocation->ToObject(&allocation)) {
7706 Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
7707 }
7708 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007709 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007710}
7711
7712
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007713// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007714// array. Returns true if the element was pushed on the stack and
7715// false otherwise.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007716static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007717 ASSERT(args.length() == 2);
7718 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007719 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007720 RUNTIME_ASSERT(array->HasFastElements());
7721 int length = Smi::cast(array->length())->value();
7722 FixedArray* elements = FixedArray::cast(array->elements());
7723 for (int i = 0; i < length; i++) {
7724 if (elements->get(i) == element) return Heap::false_value();
7725 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007726 Object* obj;
7727 { MaybeObject* maybe_obj = array->SetFastElement(length, element);
7728 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7729 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007730 return Heap::true_value();
7731}
7732
7733
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007734/**
7735 * A simple visitor visits every element of Array's.
7736 * The backend storage can be a fixed array for fast elements case,
7737 * or a dictionary for sparse array. Since Dictionary is a subtype
7738 * of FixedArray, the class can be used by both fast and slow cases.
7739 * The second parameter of the constructor, fast_elements, specifies
7740 * whether the storage is a FixedArray or Dictionary.
7741 *
7742 * An index limit is used to deal with the situation that a result array
7743 * length overflows 32-bit non-negative integer.
7744 */
7745class ArrayConcatVisitor {
7746 public:
7747 ArrayConcatVisitor(Handle<FixedArray> storage,
7748 uint32_t index_limit,
7749 bool fast_elements) :
7750 storage_(storage), index_limit_(index_limit),
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007751 index_offset_(0), fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007752
7753 void visit(uint32_t i, Handle<Object> elm) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007754 if (i >= index_limit_ - index_offset_) return;
7755 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007756
7757 if (fast_elements_) {
7758 ASSERT(index < static_cast<uint32_t>(storage_->length()));
7759 storage_->set(index, *elm);
7760
7761 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007762 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
7763 Handle<NumberDictionary> result =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007764 Factory::DictionaryAtNumberPut(dict, index, elm);
7765 if (!result.is_identical_to(dict))
7766 storage_ = result;
7767 }
7768 }
7769
7770 void increase_index_offset(uint32_t delta) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007771 if (index_limit_ - index_offset_ < delta) {
7772 index_offset_ = index_limit_;
7773 } else {
7774 index_offset_ += delta;
7775 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007776 }
7777
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007778 Handle<FixedArray> storage() { return storage_; }
7779
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007780 private:
7781 Handle<FixedArray> storage_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007782 // Limit on the accepted indices. Elements with indices larger than the
7783 // limit are ignored by the visitor.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007784 uint32_t index_limit_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007785 // Index after last seen index. Always less than or equal to index_limit_.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007786 uint32_t index_offset_;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007787 const bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007788};
7789
7790
ager@chromium.org3811b432009-10-28 14:53:37 +00007791template<class ExternalArrayClass, class ElementType>
7792static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver,
7793 bool elements_are_ints,
7794 bool elements_are_guaranteed_smis,
7795 uint32_t range,
7796 ArrayConcatVisitor* visitor) {
7797 Handle<ExternalArrayClass> array(
7798 ExternalArrayClass::cast(receiver->elements()));
7799 uint32_t len = Min(static_cast<uint32_t>(array->length()), range);
7800
7801 if (visitor != NULL) {
7802 if (elements_are_ints) {
7803 if (elements_are_guaranteed_smis) {
7804 for (uint32_t j = 0; j < len; j++) {
7805 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
7806 visitor->visit(j, e);
7807 }
7808 } else {
7809 for (uint32_t j = 0; j < len; j++) {
7810 int64_t val = static_cast<int64_t>(array->get(j));
7811 if (Smi::IsValid(static_cast<intptr_t>(val))) {
7812 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
7813 visitor->visit(j, e);
7814 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007815 Handle<Object> e =
7816 Factory::NewNumber(static_cast<ElementType>(val));
ager@chromium.org3811b432009-10-28 14:53:37 +00007817 visitor->visit(j, e);
7818 }
7819 }
7820 }
7821 } else {
7822 for (uint32_t j = 0; j < len; j++) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007823 Handle<Object> e = Factory::NewNumber(array->get(j));
ager@chromium.org3811b432009-10-28 14:53:37 +00007824 visitor->visit(j, e);
7825 }
7826 }
7827 }
7828
7829 return len;
7830}
7831
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007832/**
7833 * A helper function that visits elements of a JSObject. Only elements
7834 * whose index between 0 and range (exclusive) are visited.
7835 *
7836 * If the third parameter, visitor, is not NULL, the visitor is called
7837 * with parameters, 'visitor_index_offset + element index' and the element.
7838 *
7839 * It returns the number of visisted elements.
7840 */
7841static uint32_t IterateElements(Handle<JSObject> receiver,
7842 uint32_t range,
7843 ArrayConcatVisitor* visitor) {
7844 uint32_t num_of_elements = 0;
7845
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007846 switch (receiver->GetElementsKind()) {
7847 case JSObject::FAST_ELEMENTS: {
7848 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
7849 uint32_t len = elements->length();
7850 if (range < len) {
7851 len = range;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007852 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007853
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007854 for (uint32_t j = 0; j < len; j++) {
7855 Handle<Object> e(elements->get(j));
7856 if (!e->IsTheHole()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007857 num_of_elements++;
7858 if (visitor) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007859 visitor->visit(j, e);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007860 }
7861 }
7862 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007863 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007864 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007865 case JSObject::PIXEL_ELEMENTS: {
7866 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
7867 uint32_t len = pixels->length();
7868 if (range < len) {
7869 len = range;
7870 }
7871
7872 for (uint32_t j = 0; j < len; j++) {
7873 num_of_elements++;
7874 if (visitor != NULL) {
7875 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
7876 visitor->visit(j, e);
7877 }
7878 }
7879 break;
7880 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007881 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
7882 num_of_elements =
7883 IterateExternalArrayElements<ExternalByteArray, int8_t>(
7884 receiver, true, true, range, visitor);
7885 break;
7886 }
7887 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
7888 num_of_elements =
7889 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
7890 receiver, true, true, range, visitor);
7891 break;
7892 }
7893 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
7894 num_of_elements =
7895 IterateExternalArrayElements<ExternalShortArray, int16_t>(
7896 receiver, true, true, range, visitor);
7897 break;
7898 }
7899 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
7900 num_of_elements =
7901 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
7902 receiver, true, true, range, visitor);
7903 break;
7904 }
7905 case JSObject::EXTERNAL_INT_ELEMENTS: {
7906 num_of_elements =
7907 IterateExternalArrayElements<ExternalIntArray, int32_t>(
7908 receiver, true, false, range, visitor);
7909 break;
7910 }
7911 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
7912 num_of_elements =
7913 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
7914 receiver, true, false, range, visitor);
7915 break;
7916 }
7917 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
7918 num_of_elements =
7919 IterateExternalArrayElements<ExternalFloatArray, float>(
7920 receiver, false, false, range, visitor);
7921 break;
7922 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007923 case JSObject::DICTIONARY_ELEMENTS: {
7924 Handle<NumberDictionary> dict(receiver->element_dictionary());
7925 uint32_t capacity = dict->Capacity();
7926 for (uint32_t j = 0; j < capacity; j++) {
7927 Handle<Object> k(dict->KeyAt(j));
7928 if (dict->IsKey(*k)) {
7929 ASSERT(k->IsNumber());
7930 uint32_t index = static_cast<uint32_t>(k->Number());
7931 if (index < range) {
7932 num_of_elements++;
7933 if (visitor) {
7934 visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
7935 }
7936 }
7937 }
7938 }
7939 break;
7940 }
7941 default:
7942 UNREACHABLE();
7943 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007944 }
7945
7946 return num_of_elements;
7947}
7948
7949
7950/**
7951 * A helper function that visits elements of an Array object, and elements
7952 * on its prototypes.
7953 *
7954 * Elements on prototypes are visited first, and only elements whose indices
7955 * less than Array length are visited.
7956 *
7957 * If a ArrayConcatVisitor object is given, the visitor is called with
7958 * parameters, element's index + visitor_index_offset and the element.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007959 *
7960 * The returned number of elements is an upper bound on the actual number
7961 * of elements added. If the same element occurs in more than one object
7962 * in the array's prototype chain, it will be counted more than once, but
7963 * will only occur once in the result.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007964 */
7965static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
7966 ArrayConcatVisitor* visitor) {
7967 uint32_t range = static_cast<uint32_t>(array->length()->Number());
7968 Handle<Object> obj = array;
7969
7970 static const int kEstimatedPrototypes = 3;
7971 List< Handle<JSObject> > objects(kEstimatedPrototypes);
7972
7973 // Visit prototype first. If an element on the prototype is shadowed by
7974 // the inheritor using the same index, the ArrayConcatVisitor visits
7975 // the prototype element before the shadowing element.
7976 // The visitor can simply overwrite the old value by new value using
7977 // the same index. This follows Array::concat semantics.
7978 while (!obj->IsNull()) {
7979 objects.Add(Handle<JSObject>::cast(obj));
7980 obj = Handle<Object>(obj->GetPrototype());
7981 }
7982
7983 uint32_t nof_elements = 0;
7984 for (int i = objects.length() - 1; i >= 0; i--) {
7985 Handle<JSObject> obj = objects[i];
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007986 uint32_t encountered_elements =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007987 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007988
7989 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
7990 nof_elements = JSObject::kMaxElementCount;
7991 } else {
7992 nof_elements += encountered_elements;
7993 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007994 }
7995
7996 return nof_elements;
7997}
7998
7999
8000/**
8001 * A helper function of Runtime_ArrayConcat.
8002 *
8003 * The first argument is an Array of arrays and objects. It is the
8004 * same as the arguments array of Array::concat JS function.
8005 *
8006 * If an argument is an Array object, the function visits array
8007 * elements. If an argument is not an Array object, the function
8008 * visits the object as if it is an one-element array.
8009 *
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008010 * If the result array index overflows 32-bit unsigned integer, the rounded
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008011 * non-negative number is used as new length. For example, if one
8012 * array length is 2^32 - 1, second array length is 1, the
8013 * concatenated array length is 0.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008014 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
8015 * is one more than the last array index to get a value assigned).
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008016 */
8017static uint32_t IterateArguments(Handle<JSArray> arguments,
8018 ArrayConcatVisitor* visitor) {
8019 uint32_t visited_elements = 0;
8020 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
8021
8022 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008023 Object *element;
8024 MaybeObject* maybe_element = arguments->GetElement(i);
8025 // This if() is not expected to fail, but we have the check in the
8026 // interest of hardening the runtime calls.
8027 if (maybe_element->ToObject(&element)) {
8028 Handle<Object> obj(element);
8029 if (obj->IsJSArray()) {
8030 Handle<JSArray> array = Handle<JSArray>::cast(obj);
8031 uint32_t len = static_cast<uint32_t>(array->length()->Number());
8032 uint32_t nof_elements =
8033 IterateArrayAndPrototypeElements(array, visitor);
8034 // Total elements of array and its prototype chain can be more than
8035 // the array length, but ArrayConcat can only concatenate at most
8036 // the array length number of elements. We use the length as an estimate
8037 // for the actual number of elements added.
8038 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
8039 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
8040 visited_elements = JSArray::kMaxElementCount;
8041 } else {
8042 visited_elements += added_elements;
8043 }
8044 if (visitor) visitor->increase_index_offset(len);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008045 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008046 if (visitor) {
8047 visitor->visit(0, obj);
8048 visitor->increase_index_offset(1);
8049 }
8050 if (visited_elements < JSArray::kMaxElementCount) {
8051 visited_elements++;
8052 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008053 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008054 }
8055 }
8056 return visited_elements;
8057}
8058
8059
8060/**
8061 * Array::concat implementation.
8062 * See ECMAScript 262, 15.4.4.4.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008063 * TODO(lrn): Fix non-compliance for very large concatenations and update to
8064 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008065 */
lrn@chromium.org303ada72010-10-27 09:33:13 +00008066static MaybeObject* Runtime_ArrayConcat(Arguments args) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008067 ASSERT(args.length() == 1);
8068 HandleScope handle_scope;
8069
8070 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
8071 Handle<JSArray> arguments(arg_arrays);
8072
8073 // Pass 1: estimate the number of elements of the result
8074 // (it could be more than real numbers if prototype has elements).
8075 uint32_t result_length = 0;
8076 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
8077
8078 { AssertNoAllocation nogc;
8079 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008080 Object* obj;
8081 MaybeObject* maybe_object = arguments->GetElement(i);
8082 // This if() is not expected to fail, but we have the check in the
8083 // interest of hardening the runtime calls.
8084 if (maybe_object->ToObject(&obj)) {
8085 uint32_t length_estimate;
8086 if (obj->IsJSArray()) {
8087 length_estimate =
8088 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
8089 } else {
8090 length_estimate = 1;
8091 }
8092 if (JSObject::kMaxElementCount - result_length < length_estimate) {
8093 result_length = JSObject::kMaxElementCount;
8094 break;
8095 }
8096 result_length += length_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008097 }
8098 }
8099 }
8100
8101 // Allocate an empty array, will set length and content later.
8102 Handle<JSArray> result = Factory::NewJSArray(0);
8103
8104 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
8105 // If estimated number of elements is more than half of length, a
8106 // fixed array (fast case) is more time and space-efficient than a
8107 // dictionary.
8108 bool fast_case = (estimate_nof_elements * 2) >= result_length;
8109
8110 Handle<FixedArray> storage;
8111 if (fast_case) {
8112 // The backing storage array must have non-existing elements to
8113 // preserve holes across concat operations.
8114 storage = Factory::NewFixedArrayWithHoles(result_length);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008115 Handle<Map> fast_map =
8116 Factory::GetFastElementsMap(Handle<Map>(result->map()));
8117 result->set_map(*fast_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008118 } else {
8119 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8120 uint32_t at_least_space_for = estimate_nof_elements +
8121 (estimate_nof_elements >> 2);
8122 storage = Handle<FixedArray>::cast(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008123 Factory::NewNumberDictionary(at_least_space_for));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008124 Handle<Map> slow_map =
8125 Factory::GetSlowElementsMap(Handle<Map>(result->map()));
8126 result->set_map(*slow_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008127 }
8128
8129 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
8130
8131 ArrayConcatVisitor visitor(storage, result_length, fast_case);
8132
8133 IterateArguments(arguments, &visitor);
8134
8135 result->set_length(*len);
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008136 // Please note the storage might have changed in the visitor.
8137 result->set_elements(*visitor.storage());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008138
8139 return *result;
8140}
8141
8142
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008143// This will not allocate (flatten the string), but it may run
8144// very slowly for very deeply nested ConsStrings. For debugging use only.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008145static MaybeObject* Runtime_GlobalPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008146 NoHandleAllocation ha;
8147 ASSERT(args.length() == 1);
8148
8149 CONVERT_CHECKED(String, string, args[0]);
8150 StringInputBuffer buffer(string);
8151 while (buffer.has_more()) {
8152 uint16_t character = buffer.GetNext();
8153 PrintF("%c", character);
8154 }
8155 return string;
8156}
8157
ager@chromium.org5ec48922009-05-05 07:25:34 +00008158// Moves all own elements of an object, that are below a limit, to positions
8159// starting at zero. All undefined values are placed after non-undefined values,
8160// and are followed by non-existing element. Does not change the length
8161// property.
8162// Returns the number of non-undefined elements collected.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008163static MaybeObject* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008164 ASSERT(args.length() == 2);
8165 CONVERT_CHECKED(JSObject, object, args[0]);
8166 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
8167 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008168}
8169
8170
8171// Move contents of argument 0 (an array) to argument 1 (an array)
lrn@chromium.org303ada72010-10-27 09:33:13 +00008172static MaybeObject* Runtime_MoveArrayContents(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008173 ASSERT(args.length() == 2);
8174 CONVERT_CHECKED(JSArray, from, args[0]);
8175 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008176 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008177 MaybeObject* maybe_new_map;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00008178 if (new_elements->map() == Heap::fixed_array_map() ||
8179 new_elements->map() == Heap::fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008180 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008181 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008182 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008183 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008184 Object* new_map;
8185 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008186 to->set_map(Map::cast(new_map));
8187 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008188 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008189 Object* obj;
8190 { MaybeObject* maybe_obj = from->ResetElements();
8191 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8192 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008193 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008194 return to;
8195}
8196
8197
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008198// How many elements does this object/array have?
lrn@chromium.org303ada72010-10-27 09:33:13 +00008199static MaybeObject* Runtime_EstimateNumberOfElements(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008200 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008201 CONVERT_CHECKED(JSObject, object, args[0]);
8202 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008203 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008204 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008205 } else if (object->IsJSArray()) {
8206 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008207 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008208 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008209 }
8210}
8211
8212
lrn@chromium.org303ada72010-10-27 09:33:13 +00008213static MaybeObject* Runtime_SwapElements(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008214 HandleScope handle_scope;
8215
8216 ASSERT_EQ(3, args.length());
8217
ager@chromium.orgac091b72010-05-05 07:34:42 +00008218 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008219 Handle<Object> key1 = args.at<Object>(1);
8220 Handle<Object> key2 = args.at<Object>(2);
8221
8222 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008223 if (!key1->ToArrayIndex(&index1)
8224 || !key2->ToArrayIndex(&index2)) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00008225 return Top::ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008226 }
8227
ager@chromium.orgac091b72010-05-05 07:34:42 +00008228 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
8229 Handle<Object> tmp1 = GetElement(jsobject, index1);
8230 Handle<Object> tmp2 = GetElement(jsobject, index2);
8231
8232 SetElement(jsobject, index1, tmp2);
8233 SetElement(jsobject, index2, tmp1);
8234
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008235 return Heap::undefined_value();
8236}
8237
8238
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008239// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008240// might have elements. Can either return keys (positive integers) or
8241// intervals (pair of a negative integer (-start-1) followed by a
8242// positive (length)) or undefined values.
8243// Intervals can span over some keys that are not in the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008244static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008245 ASSERT(args.length() == 2);
8246 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008247 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008248 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008249 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008250 // Create an array and get all the keys into it, then remove all the
8251 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008252 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008253 int keys_length = keys->length();
8254 for (int i = 0; i < keys_length; i++) {
8255 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008256 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008257 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008258 // Zap invalid keys.
8259 keys->set_undefined(i);
8260 }
8261 }
8262 return *Factory::NewJSArrayWithElements(keys);
8263 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008264 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008265 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
8266 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008267 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008268 uint32_t actual_length =
8269 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00008270 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008271 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00008272 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008273 single_interval->set(1, *length_object);
8274 return *Factory::NewJSArrayWithElements(single_interval);
8275 }
8276}
8277
8278
8279// DefineAccessor takes an optional final argument which is the
8280// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
8281// to the way accessors are implemented, it is set for both the getter
8282// and setter on the first call to DefineAccessor and ignored on
8283// subsequent calls.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008284static MaybeObject* Runtime_DefineAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008285 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
8286 // Compute attributes.
8287 PropertyAttributes attributes = NONE;
8288 if (args.length() == 5) {
8289 CONVERT_CHECKED(Smi, attrs, args[4]);
8290 int value = attrs->value();
8291 // Only attribute bits should be set.
8292 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
8293 attributes = static_cast<PropertyAttributes>(value);
8294 }
8295
8296 CONVERT_CHECKED(JSObject, obj, args[0]);
8297 CONVERT_CHECKED(String, name, args[1]);
8298 CONVERT_CHECKED(Smi, flag, args[2]);
8299 CONVERT_CHECKED(JSFunction, fun, args[3]);
8300 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
8301}
8302
8303
lrn@chromium.org303ada72010-10-27 09:33:13 +00008304static MaybeObject* Runtime_LookupAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008305 ASSERT(args.length() == 3);
8306 CONVERT_CHECKED(JSObject, obj, args[0]);
8307 CONVERT_CHECKED(String, name, args[1]);
8308 CONVERT_CHECKED(Smi, flag, args[2]);
8309 return obj->LookupAccessor(name, flag->value() == 0);
8310}
8311
8312
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008313#ifdef ENABLE_DEBUGGER_SUPPORT
lrn@chromium.org303ada72010-10-27 09:33:13 +00008314static MaybeObject* Runtime_DebugBreak(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008315 ASSERT(args.length() == 0);
8316 return Execution::DebugBreakHelper();
8317}
8318
8319
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008320// Helper functions for wrapping and unwrapping stack frame ids.
8321static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008322 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008323 return Smi::FromInt(id >> 2);
8324}
8325
8326
8327static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
8328 return static_cast<StackFrame::Id>(wrapped->value() << 2);
8329}
8330
8331
8332// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00008333// args[0]: debug event listener function to set or null or undefined for
8334// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008335// args[1]: object supplied during callback
lrn@chromium.org303ada72010-10-27 09:33:13 +00008336static MaybeObject* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008337 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008338 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
8339 args[0]->IsUndefined() ||
8340 args[0]->IsNull());
8341 Handle<Object> callback = args.at<Object>(0);
8342 Handle<Object> data = args.at<Object>(1);
8343 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008344
8345 return Heap::undefined_value();
8346}
8347
8348
lrn@chromium.org303ada72010-10-27 09:33:13 +00008349static MaybeObject* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00008350 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008351 StackGuard::DebugBreak();
8352 return Heap::undefined_value();
8353}
8354
8355
lrn@chromium.org303ada72010-10-27 09:33:13 +00008356static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
8357 LookupResult* result,
8358 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008359 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008360 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008361 case NORMAL:
8362 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008363 if (value->IsTheHole()) {
8364 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008365 }
8366 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008367 case FIELD:
8368 value =
8369 JSObject::cast(
8370 result->holder())->FastPropertyAt(result->GetFieldIndex());
8371 if (value->IsTheHole()) {
8372 return Heap::undefined_value();
8373 }
8374 return value;
8375 case CONSTANT_FUNCTION:
8376 return result->GetConstantFunction();
8377 case CALLBACKS: {
8378 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008379 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008380 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008381 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008382 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008383 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008384 ASSERT(maybe_value->IsException());
8385 maybe_value = Top::pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008386 Top::clear_pending_exception();
8387 if (caught_exception != NULL) {
8388 *caught_exception = true;
8389 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008390 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008391 }
8392 return value;
8393 } else {
8394 return Heap::undefined_value();
8395 }
8396 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008397 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008398 case MAP_TRANSITION:
8399 case CONSTANT_TRANSITION:
8400 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008401 return Heap::undefined_value();
8402 default:
8403 UNREACHABLE();
8404 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008405 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008406 return Heap::undefined_value();
8407}
8408
8409
ager@chromium.org32912102009-01-16 10:38:43 +00008410// Get debugger related details for an object property.
8411// args[0]: object holding property
8412// args[1]: name of the property
8413//
8414// The array returned contains the following information:
8415// 0: Property value
8416// 1: Property details
8417// 2: Property value is exception
8418// 3: Getter function if defined
8419// 4: Setter function if defined
8420// Items 2-4 are only filled if the property has either a getter or a setter
8421// defined through __defineGetter__ and/or __defineSetter__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008422static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008423 HandleScope scope;
8424
8425 ASSERT(args.length() == 2);
8426
8427 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8428 CONVERT_ARG_CHECKED(String, name, 1);
8429
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008430 // Make sure to set the current context to the context before the debugger was
8431 // entered (if the debugger is entered). The reason for switching context here
8432 // is that for some property lookups (accessors and interceptors) callbacks
8433 // into the embedding application can occour, and the embedding application
8434 // could have the assumption that its own global context is the current
8435 // context and not some internal debugger context.
8436 SaveContext save;
8437 if (Debug::InDebugger()) {
8438 Top::set_context(*Debug::debugger_entry()->GetContext());
8439 }
8440
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008441 // Skip the global proxy as it has no properties and always delegates to the
8442 // real global object.
8443 if (obj->IsJSGlobalProxy()) {
8444 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
8445 }
8446
8447
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008448 // Check if the name is trivially convertible to an index and get the element
8449 // if so.
8450 uint32_t index;
8451 if (name->AsArrayIndex(&index)) {
8452 Handle<FixedArray> details = Factory::NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008453 Object* element_or_char;
8454 { MaybeObject* maybe_element_or_char =
8455 Runtime::GetElementOrCharAt(obj, index);
8456 if (!maybe_element_or_char->ToObject(&element_or_char)) {
8457 return maybe_element_or_char;
8458 }
8459 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008460 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008461 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
8462 return *Factory::NewJSArrayWithElements(details);
8463 }
8464
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008465 // Find the number of objects making up this.
8466 int length = LocalPrototypeChainLength(*obj);
8467
8468 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008469 Handle<JSObject> jsproto = obj;
8470 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008471 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008472 jsproto->LocalLookup(*name, &result);
8473 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008474 // LookupResult is not GC safe as it holds raw object pointers.
8475 // GC can happen later in this code so put the required fields into
8476 // local variables using handles when required for later use.
8477 PropertyType result_type = result.type();
8478 Handle<Object> result_callback_obj;
8479 if (result_type == CALLBACKS) {
8480 result_callback_obj = Handle<Object>(result.GetCallbackObject());
8481 }
8482 Smi* property_details = result.GetPropertyDetails().AsSmi();
8483 // DebugLookupResultValue can cause GC so details from LookupResult needs
8484 // to be copied to handles before this.
8485 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008486 Object* raw_value;
8487 { MaybeObject* maybe_raw_value =
8488 DebugLookupResultValue(*obj, *name, &result, &caught_exception);
8489 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
8490 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008491 Handle<Object> value(raw_value);
8492
8493 // If the callback object is a fixed array then it contains JavaScript
8494 // getter and/or setter.
8495 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
8496 result_callback_obj->IsFixedArray();
8497 Handle<FixedArray> details =
8498 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
8499 details->set(0, *value);
8500 details->set(1, property_details);
8501 if (hasJavaScriptAccessors) {
8502 details->set(2,
8503 caught_exception ? Heap::true_value()
8504 : Heap::false_value());
8505 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
8506 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
8507 }
8508
8509 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008510 }
8511 if (i < length - 1) {
8512 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
8513 }
8514 }
8515
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008516 return Heap::undefined_value();
8517}
8518
8519
lrn@chromium.org303ada72010-10-27 09:33:13 +00008520static MaybeObject* Runtime_DebugGetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008521 HandleScope scope;
8522
8523 ASSERT(args.length() == 2);
8524
8525 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8526 CONVERT_ARG_CHECKED(String, name, 1);
8527
8528 LookupResult result;
8529 obj->Lookup(*name, &result);
8530 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008531 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008532 }
8533 return Heap::undefined_value();
8534}
8535
8536
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008537// Return the property type calculated from the property details.
8538// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008539static MaybeObject* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008540 ASSERT(args.length() == 1);
8541 CONVERT_CHECKED(Smi, details, args[0]);
8542 PropertyType type = PropertyDetails(details).type();
8543 return Smi::FromInt(static_cast<int>(type));
8544}
8545
8546
8547// Return the property attribute calculated from the property details.
8548// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008549static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008550 ASSERT(args.length() == 1);
8551 CONVERT_CHECKED(Smi, details, args[0]);
8552 PropertyAttributes attributes = PropertyDetails(details).attributes();
8553 return Smi::FromInt(static_cast<int>(attributes));
8554}
8555
8556
8557// Return the property insertion index calculated from the property details.
8558// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008559static MaybeObject* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008560 ASSERT(args.length() == 1);
8561 CONVERT_CHECKED(Smi, details, args[0]);
8562 int index = PropertyDetails(details).index();
8563 return Smi::FromInt(index);
8564}
8565
8566
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008567// Return property value from named interceptor.
8568// args[0]: object
8569// args[1]: property name
lrn@chromium.org303ada72010-10-27 09:33:13 +00008570static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008571 HandleScope scope;
8572 ASSERT(args.length() == 2);
8573 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8574 RUNTIME_ASSERT(obj->HasNamedInterceptor());
8575 CONVERT_ARG_CHECKED(String, name, 1);
8576
8577 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008578 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008579}
8580
8581
8582// Return element value from indexed interceptor.
8583// args[0]: object
8584// args[1]: index
lrn@chromium.org303ada72010-10-27 09:33:13 +00008585static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
8586 Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008587 HandleScope scope;
8588 ASSERT(args.length() == 2);
8589 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8590 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
8591 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
8592
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008593 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008594}
8595
8596
lrn@chromium.org303ada72010-10-27 09:33:13 +00008597static MaybeObject* Runtime_CheckExecutionState(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008598 ASSERT(args.length() >= 1);
8599 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00008600 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008601 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008602 return Top::Throw(Heap::illegal_execution_state_symbol());
8603 }
8604
8605 return Heap::true_value();
8606}
8607
8608
lrn@chromium.org303ada72010-10-27 09:33:13 +00008609static MaybeObject* Runtime_GetFrameCount(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008610 HandleScope scope;
8611 ASSERT(args.length() == 1);
8612
8613 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008614 Object* result;
8615 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
8616 if (!maybe_result->ToObject(&result)) return maybe_result;
8617 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008618
8619 // Count all frames which are relevant to debugging stack trace.
8620 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008621 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008622 if (id == StackFrame::NO_ID) {
8623 // If there is no JavaScript stack frame count is 0.
8624 return Smi::FromInt(0);
8625 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008626 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
8627 return Smi::FromInt(n);
8628}
8629
8630
8631static const int kFrameDetailsFrameIdIndex = 0;
8632static const int kFrameDetailsReceiverIndex = 1;
8633static const int kFrameDetailsFunctionIndex = 2;
8634static const int kFrameDetailsArgumentCountIndex = 3;
8635static const int kFrameDetailsLocalCountIndex = 4;
8636static const int kFrameDetailsSourcePositionIndex = 5;
8637static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008638static const int kFrameDetailsAtReturnIndex = 7;
8639static const int kFrameDetailsDebuggerFrameIndex = 8;
8640static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008641
8642// Return an array with frame details
8643// args[0]: number: break id
8644// args[1]: number: frame index
8645//
8646// The array returned contains the following information:
8647// 0: Frame id
8648// 1: Receiver
8649// 2: Function
8650// 3: Argument count
8651// 4: Local count
8652// 5: Source position
8653// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008654// 7: Is at return
8655// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008656// Arguments name, value
8657// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008658// Return value if any
lrn@chromium.org303ada72010-10-27 09:33:13 +00008659static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008660 HandleScope scope;
8661 ASSERT(args.length() == 2);
8662
8663 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008664 Object* check;
8665 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8666 if (!maybe_check->ToObject(&check)) return maybe_check;
8667 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008668 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8669
8670 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008671 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008672 if (id == StackFrame::NO_ID) {
8673 // If there are no JavaScript stack frames return undefined.
8674 return Heap::undefined_value();
8675 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008676 int count = 0;
8677 JavaScriptFrameIterator it(id);
8678 for (; !it.done(); it.Advance()) {
8679 if (count == index) break;
8680 count++;
8681 }
8682 if (it.done()) return Heap::undefined_value();
8683
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008684 bool is_optimized_frame =
8685 it.frame()->code()->kind() == Code::OPTIMIZED_FUNCTION;
8686
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008687 // Traverse the saved contexts chain to find the active context for the
8688 // selected frame.
8689 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008690 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008691 save = save->prev();
8692 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008693 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008694
8695 // Get the frame id.
8696 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
8697
8698 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00008699 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008700
8701 // Check for constructor frame.
8702 bool constructor = it.frame()->IsConstructor();
8703
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008704 // Get scope info and read from it for local variable information.
8705 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00008706 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008707 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008708
8709 // Get the context.
8710 Handle<Context> context(Context::cast(it.frame()->context()));
8711
8712 // Get the locals names and values into a temporary array.
8713 //
8714 // TODO(1240907): Hide compiler-introduced stack variables
8715 // (e.g. .result)? For users of the debugger, they will probably be
8716 // confusing.
8717 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008718
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008719 // Fill in the names of the locals.
8720 for (int i = 0; i < info.NumberOfLocals(); i++) {
8721 locals->set(i * 2, *info.LocalName(i));
8722 }
8723
8724 // Fill in the values of the locals.
8725 for (int i = 0; i < info.NumberOfLocals(); i++) {
8726 if (is_optimized_frame) {
8727 // If we are inspecting an optimized frame use undefined as the
8728 // value for all locals.
8729 //
8730 // TODO(3141533): We should be able to get the correct values
8731 // for locals in optimized frames.
8732 locals->set(i * 2 + 1, Heap::undefined_value());
8733 } else if (i < info.number_of_stack_slots()) {
8734 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008735 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
8736 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008737 // Traverse the context chain to the function context as all local
8738 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008739 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008740 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008741 context = Handle<Context>(context->previous());
8742 }
8743 ASSERT(context->is_function_context());
8744 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00008745 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008746 }
8747 }
8748
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008749 // Check whether this frame is positioned at return. If not top
8750 // frame or if the frame is optimized it cannot be at a return.
8751 bool at_return = false;
8752 if (!is_optimized_frame && index == 0) {
8753 at_return = Debug::IsBreakAtReturn(it.frame());
8754 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008755
8756 // If positioned just before return find the value to be returned and add it
8757 // to the frame information.
8758 Handle<Object> return_value = Factory::undefined_value();
8759 if (at_return) {
8760 StackFrameIterator it2;
8761 Address internal_frame_sp = NULL;
8762 while (!it2.done()) {
8763 if (it2.frame()->is_internal()) {
8764 internal_frame_sp = it2.frame()->sp();
8765 } else {
8766 if (it2.frame()->is_java_script()) {
8767 if (it2.frame()->id() == it.frame()->id()) {
8768 // The internal frame just before the JavaScript frame contains the
8769 // value to return on top. A debug break at return will create an
8770 // internal frame to store the return value (eax/rax/r0) before
8771 // entering the debug break exit frame.
8772 if (internal_frame_sp != NULL) {
8773 return_value =
8774 Handle<Object>(Memory::Object_at(internal_frame_sp));
8775 break;
8776 }
8777 }
8778 }
8779
8780 // Indicate that the previous frame was not an internal frame.
8781 internal_frame_sp = NULL;
8782 }
8783 it2.Advance();
8784 }
8785 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008786
8787 // Now advance to the arguments adapter frame (if any). It contains all
8788 // the provided parameters whereas the function frame always have the number
8789 // of arguments matching the functions parameters. The rest of the
8790 // information (except for what is collected above) is the same.
8791 it.AdvanceToArgumentsFrame();
8792
8793 // Find the number of arguments to fill. At least fill the number of
8794 // parameters for the function and fill more if more parameters are provided.
8795 int argument_count = info.number_of_parameters();
8796 if (argument_count < it.frame()->GetProvidedParametersCount()) {
8797 argument_count = it.frame()->GetProvidedParametersCount();
8798 }
8799
8800 // Calculate the size of the result.
8801 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008802 2 * (argument_count + info.NumberOfLocals()) +
8803 (at_return ? 1 : 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008804 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8805
8806 // Add the frame id.
8807 details->set(kFrameDetailsFrameIdIndex, *frame_id);
8808
8809 // Add the function (same as in function frame).
8810 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
8811
8812 // Add the arguments count.
8813 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
8814
8815 // Add the locals count
8816 details->set(kFrameDetailsLocalCountIndex,
8817 Smi::FromInt(info.NumberOfLocals()));
8818
8819 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00008820 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008821 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
8822 } else {
8823 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
8824 }
8825
8826 // Add the constructor information.
8827 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
8828
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008829 // Add the at return information.
8830 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
8831
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008832 // Add information on whether this frame is invoked in the debugger context.
8833 details->set(kFrameDetailsDebuggerFrameIndex,
8834 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
8835
8836 // Fill the dynamic part.
8837 int details_index = kFrameDetailsFirstDynamicIndex;
8838
8839 // Add arguments name and value.
8840 for (int i = 0; i < argument_count; i++) {
8841 // Name of the argument.
8842 if (i < info.number_of_parameters()) {
8843 details->set(details_index++, *info.parameter_name(i));
8844 } else {
8845 details->set(details_index++, Heap::undefined_value());
8846 }
8847
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008848 // Parameter value. If we are inspecting an optimized frame, use
8849 // undefined as the value.
8850 //
8851 // TODO(3141533): We should be able to get the actual parameter
8852 // value for optimized frames.
8853 if (!is_optimized_frame &&
8854 (i < it.frame()->GetProvidedParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008855 details->set(details_index++, it.frame()->GetParameter(i));
8856 } else {
8857 details->set(details_index++, Heap::undefined_value());
8858 }
8859 }
8860
8861 // Add locals name and value from the temporary copy from the function frame.
8862 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
8863 details->set(details_index++, locals->get(i));
8864 }
8865
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008866 // Add the value being returned.
8867 if (at_return) {
8868 details->set(details_index++, *return_value);
8869 }
8870
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008871 // Add the receiver (same as in function frame).
8872 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
8873 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
8874 Handle<Object> receiver(it.frame()->receiver());
8875 if (!receiver->IsJSObject()) {
8876 // If the receiver is NOT a JSObject we have hit an optimization
8877 // where a value object is not converted into a wrapped JS objects.
8878 // To hide this optimization from the debugger, we wrap the receiver
8879 // by creating correct wrapper object based on the calling frame's
8880 // global context.
8881 it.Advance();
8882 Handle<Context> calling_frames_global_context(
8883 Context::cast(Context::cast(it.frame()->context())->global_context()));
8884 receiver = Factory::ToObject(receiver, calling_frames_global_context);
8885 }
8886 details->set(kFrameDetailsReceiverIndex, *receiver);
8887
8888 ASSERT_EQ(details_size, details_index);
8889 return *Factory::NewJSArrayWithElements(details);
8890}
8891
8892
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008893// Copy all the context locals into an object used to materialize a scope.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008894static void CopyContextLocalsToScopeObject(
8895 Handle<SerializedScopeInfo> serialized_scope_info,
8896 ScopeInfo<>& scope_info,
8897 Handle<Context> context,
8898 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008899 // Fill all context locals to the context extension.
8900 for (int i = Context::MIN_CONTEXT_SLOTS;
8901 i < scope_info.number_of_context_slots();
8902 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00008903 int context_index = serialized_scope_info->ContextSlotIndex(
8904 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008905
8906 // Don't include the arguments shadow (.arguments) context variable.
8907 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
8908 SetProperty(scope_object,
8909 scope_info.context_slot_name(i),
8910 Handle<Object>(context->get(context_index)), NONE);
8911 }
8912 }
8913}
8914
8915
8916// Create a plain JSObject which materializes the local scope for the specified
8917// frame.
8918static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
8919 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008920 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008921 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8922 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008923
8924 // Allocate and initialize a JSObject with all the arguments, stack locals
8925 // heap locals and extension properties of the debugged function.
8926 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
8927
8928 // First fill all parameters.
8929 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
8930 SetProperty(local_scope,
8931 scope_info.parameter_name(i),
8932 Handle<Object>(frame->GetParameter(i)), NONE);
8933 }
8934
8935 // Second fill all stack locals.
8936 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
8937 SetProperty(local_scope,
8938 scope_info.stack_slot_name(i),
8939 Handle<Object>(frame->GetExpression(i)), NONE);
8940 }
8941
8942 // Third fill all context locals.
8943 Handle<Context> frame_context(Context::cast(frame->context()));
8944 Handle<Context> function_context(frame_context->fcontext());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008945 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008946 function_context, local_scope);
8947
8948 // Finally copy any properties from the function context extension. This will
8949 // be variables introduced by eval.
8950 if (function_context->closure() == *function) {
8951 if (function_context->has_extension() &&
8952 !function_context->IsGlobalContext()) {
8953 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008954 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008955 for (int i = 0; i < keys->length(); i++) {
8956 // Names of variables introduced by eval are strings.
8957 ASSERT(keys->get(i)->IsString());
8958 Handle<String> key(String::cast(keys->get(i)));
8959 SetProperty(local_scope, key, GetProperty(ext, key), NONE);
8960 }
8961 }
8962 }
8963 return local_scope;
8964}
8965
8966
8967// Create a plain JSObject which materializes the closure content for the
8968// context.
8969static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
8970 ASSERT(context->is_function_context());
8971
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008972 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008973 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8974 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008975
8976 // Allocate and initialize a JSObject with all the content of theis function
8977 // closure.
8978 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
8979
8980 // Check whether the arguments shadow object exists.
8981 int arguments_shadow_index =
ager@chromium.orgb5737492010-07-15 09:29:43 +00008982 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
8983 NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008984 if (arguments_shadow_index >= 0) {
8985 // In this case all the arguments are available in the arguments shadow
8986 // object.
8987 Handle<JSObject> arguments_shadow(
8988 JSObject::cast(context->get(arguments_shadow_index)));
8989 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008990 // We don't expect exception-throwing getters on the arguments shadow.
8991 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008992 SetProperty(closure_scope,
8993 scope_info.parameter_name(i),
lrn@chromium.org303ada72010-10-27 09:33:13 +00008994 Handle<Object>(element),
8995 NONE);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008996 }
8997 }
8998
8999 // Fill all context locals to the context extension.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009000 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
9001 context, closure_scope);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009002
9003 // Finally copy any properties from the function context extension. This will
9004 // be variables introduced by eval.
9005 if (context->has_extension()) {
9006 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009007 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009008 for (int i = 0; i < keys->length(); i++) {
9009 // Names of variables introduced by eval are strings.
9010 ASSERT(keys->get(i)->IsString());
9011 Handle<String> key(String::cast(keys->get(i)));
9012 SetProperty(closure_scope, key, GetProperty(ext, key), NONE);
9013 }
9014 }
9015
9016 return closure_scope;
9017}
9018
9019
9020// Iterate over the actual scopes visible from a stack frame. All scopes are
9021// backed by an actual context except the local scope, which is inserted
9022// "artifically" in the context chain.
9023class ScopeIterator {
9024 public:
9025 enum ScopeType {
9026 ScopeTypeGlobal = 0,
9027 ScopeTypeLocal,
9028 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00009029 ScopeTypeClosure,
9030 // Every catch block contains an implicit with block (its parameter is
9031 // a JSContextExtensionObject) that extends current scope with a variable
9032 // holding exception object. Such with blocks are treated as scopes of their
9033 // own type.
9034 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009035 };
9036
9037 explicit ScopeIterator(JavaScriptFrame* frame)
9038 : frame_(frame),
9039 function_(JSFunction::cast(frame->function())),
9040 context_(Context::cast(frame->context())),
9041 local_done_(false),
9042 at_local_(false) {
9043
9044 // Check whether the first scope is actually a local scope.
9045 if (context_->IsGlobalContext()) {
9046 // If there is a stack slot for .result then this local scope has been
9047 // created for evaluating top level code and it is not a real local scope.
9048 // Checking for the existence of .result seems fragile, but the scope info
9049 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009050 int index = function_->shared()->scope_info()->
9051 StackSlotIndex(Heap::result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009052 at_local_ = index < 0;
9053 } else if (context_->is_function_context()) {
9054 at_local_ = true;
9055 }
9056 }
9057
9058 // More scopes?
9059 bool Done() { return context_.is_null(); }
9060
9061 // Move to the next scope.
9062 void Next() {
9063 // If at a local scope mark the local scope as passed.
9064 if (at_local_) {
9065 at_local_ = false;
9066 local_done_ = true;
9067
9068 // If the current context is not associated with the local scope the
9069 // current context is the next real scope, so don't move to the next
9070 // context in this case.
9071 if (context_->closure() != *function_) {
9072 return;
9073 }
9074 }
9075
9076 // The global scope is always the last in the chain.
9077 if (context_->IsGlobalContext()) {
9078 context_ = Handle<Context>();
9079 return;
9080 }
9081
9082 // Move to the next context.
9083 if (context_->is_function_context()) {
9084 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
9085 } else {
9086 context_ = Handle<Context>(context_->previous());
9087 }
9088
9089 // If passing the local scope indicate that the current scope is now the
9090 // local scope.
9091 if (!local_done_ &&
9092 (context_->IsGlobalContext() || (context_->is_function_context()))) {
9093 at_local_ = true;
9094 }
9095 }
9096
9097 // Return the type of the current scope.
9098 int Type() {
9099 if (at_local_) {
9100 return ScopeTypeLocal;
9101 }
9102 if (context_->IsGlobalContext()) {
9103 ASSERT(context_->global()->IsGlobalObject());
9104 return ScopeTypeGlobal;
9105 }
9106 if (context_->is_function_context()) {
9107 return ScopeTypeClosure;
9108 }
9109 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00009110 // Current scope is either an explicit with statement or a with statement
9111 // implicitely generated for a catch block.
9112 // If the extension object here is a JSContextExtensionObject then
9113 // current with statement is one frome a catch block otherwise it's a
9114 // regular with statement.
9115 if (context_->extension()->IsJSContextExtensionObject()) {
9116 return ScopeTypeCatch;
9117 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009118 return ScopeTypeWith;
9119 }
9120
9121 // Return the JavaScript object with the content of the current scope.
9122 Handle<JSObject> ScopeObject() {
9123 switch (Type()) {
9124 case ScopeIterator::ScopeTypeGlobal:
9125 return Handle<JSObject>(CurrentContext()->global());
9126 break;
9127 case ScopeIterator::ScopeTypeLocal:
9128 // Materialize the content of the local scope into a JSObject.
9129 return MaterializeLocalScope(frame_);
9130 break;
9131 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00009132 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009133 // Return the with object.
9134 return Handle<JSObject>(CurrentContext()->extension());
9135 break;
9136 case ScopeIterator::ScopeTypeClosure:
9137 // Materialize the content of the closure scope into a JSObject.
9138 return MaterializeClosure(CurrentContext());
9139 break;
9140 }
9141 UNREACHABLE();
9142 return Handle<JSObject>();
9143 }
9144
9145 // Return the context for this scope. For the local context there might not
9146 // be an actual context.
9147 Handle<Context> CurrentContext() {
9148 if (at_local_ && context_->closure() != *function_) {
9149 return Handle<Context>();
9150 }
9151 return context_;
9152 }
9153
9154#ifdef DEBUG
9155 // Debug print of the content of the current scope.
9156 void DebugPrint() {
9157 switch (Type()) {
9158 case ScopeIterator::ScopeTypeGlobal:
9159 PrintF("Global:\n");
9160 CurrentContext()->Print();
9161 break;
9162
9163 case ScopeIterator::ScopeTypeLocal: {
9164 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009165 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009166 scope_info.Print();
9167 if (!CurrentContext().is_null()) {
9168 CurrentContext()->Print();
9169 if (CurrentContext()->has_extension()) {
9170 Handle<JSObject> extension =
9171 Handle<JSObject>(CurrentContext()->extension());
9172 if (extension->IsJSContextExtensionObject()) {
9173 extension->Print();
9174 }
9175 }
9176 }
9177 break;
9178 }
9179
9180 case ScopeIterator::ScopeTypeWith: {
9181 PrintF("With:\n");
9182 Handle<JSObject> extension =
9183 Handle<JSObject>(CurrentContext()->extension());
9184 extension->Print();
9185 break;
9186 }
9187
ager@chromium.orga1645e22009-09-09 19:27:10 +00009188 case ScopeIterator::ScopeTypeCatch: {
9189 PrintF("Catch:\n");
9190 Handle<JSObject> extension =
9191 Handle<JSObject>(CurrentContext()->extension());
9192 extension->Print();
9193 break;
9194 }
9195
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009196 case ScopeIterator::ScopeTypeClosure: {
9197 PrintF("Closure:\n");
9198 CurrentContext()->Print();
9199 if (CurrentContext()->has_extension()) {
9200 Handle<JSObject> extension =
9201 Handle<JSObject>(CurrentContext()->extension());
9202 if (extension->IsJSContextExtensionObject()) {
9203 extension->Print();
9204 }
9205 }
9206 break;
9207 }
9208
9209 default:
9210 UNREACHABLE();
9211 }
9212 PrintF("\n");
9213 }
9214#endif
9215
9216 private:
9217 JavaScriptFrame* frame_;
9218 Handle<JSFunction> function_;
9219 Handle<Context> context_;
9220 bool local_done_;
9221 bool at_local_;
9222
9223 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
9224};
9225
9226
lrn@chromium.org303ada72010-10-27 09:33:13 +00009227static MaybeObject* Runtime_GetScopeCount(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009228 HandleScope scope;
9229 ASSERT(args.length() == 2);
9230
9231 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009232 Object* check;
9233 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9234 if (!maybe_check->ToObject(&check)) return maybe_check;
9235 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009236 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9237
9238 // Get the frame where the debugging is performed.
9239 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9240 JavaScriptFrameIterator it(id);
9241 JavaScriptFrame* frame = it.frame();
9242
9243 // Count the visible scopes.
9244 int n = 0;
9245 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9246 n++;
9247 }
9248
9249 return Smi::FromInt(n);
9250}
9251
9252
9253static const int kScopeDetailsTypeIndex = 0;
9254static const int kScopeDetailsObjectIndex = 1;
9255static const int kScopeDetailsSize = 2;
9256
9257// Return an array with scope details
9258// args[0]: number: break id
9259// args[1]: number: frame index
9260// args[2]: number: scope index
9261//
9262// The array returned contains the following information:
9263// 0: Scope type
9264// 1: Scope object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009265static MaybeObject* Runtime_GetScopeDetails(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009266 HandleScope scope;
9267 ASSERT(args.length() == 3);
9268
9269 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009270 Object* check;
9271 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9272 if (!maybe_check->ToObject(&check)) return maybe_check;
9273 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009274 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9275 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
9276
9277 // Get the frame where the debugging is performed.
9278 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9279 JavaScriptFrameIterator frame_it(id);
9280 JavaScriptFrame* frame = frame_it.frame();
9281
9282 // Find the requested scope.
9283 int n = 0;
9284 ScopeIterator it(frame);
9285 for (; !it.Done() && n < index; it.Next()) {
9286 n++;
9287 }
9288 if (it.Done()) {
9289 return Heap::undefined_value();
9290 }
9291
9292 // Calculate the size of the result.
9293 int details_size = kScopeDetailsSize;
9294 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9295
9296 // Fill in scope details.
9297 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009298 Handle<JSObject> scope_object = it.ScopeObject();
9299 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009300
9301 return *Factory::NewJSArrayWithElements(details);
9302}
9303
9304
lrn@chromium.org303ada72010-10-27 09:33:13 +00009305static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009306 HandleScope scope;
9307 ASSERT(args.length() == 0);
9308
9309#ifdef DEBUG
9310 // Print the scopes for the top frame.
9311 StackFrameLocator locator;
9312 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
9313 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9314 it.DebugPrint();
9315 }
9316#endif
9317 return Heap::undefined_value();
9318}
9319
9320
lrn@chromium.org303ada72010-10-27 09:33:13 +00009321static MaybeObject* Runtime_GetThreadCount(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009322 HandleScope scope;
9323 ASSERT(args.length() == 1);
9324
9325 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009326 Object* result;
9327 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
9328 if (!maybe_result->ToObject(&result)) return maybe_result;
9329 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009330
9331 // Count all archived V8 threads.
9332 int n = 0;
9333 for (ThreadState* thread = ThreadState::FirstInUse();
9334 thread != NULL;
9335 thread = thread->Next()) {
9336 n++;
9337 }
9338
9339 // Total number of threads is current thread and archived threads.
9340 return Smi::FromInt(n + 1);
9341}
9342
9343
9344static const int kThreadDetailsCurrentThreadIndex = 0;
9345static const int kThreadDetailsThreadIdIndex = 1;
9346static const int kThreadDetailsSize = 2;
9347
9348// Return an array with thread details
9349// args[0]: number: break id
9350// args[1]: number: thread index
9351//
9352// The array returned contains the following information:
9353// 0: Is current thread?
9354// 1: Thread id
lrn@chromium.org303ada72010-10-27 09:33:13 +00009355static MaybeObject* Runtime_GetThreadDetails(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009356 HandleScope scope;
9357 ASSERT(args.length() == 2);
9358
9359 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009360 Object* check;
9361 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9362 if (!maybe_check->ToObject(&check)) return maybe_check;
9363 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009364 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
9365
9366 // Allocate array for result.
9367 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
9368
9369 // Thread index 0 is current thread.
9370 if (index == 0) {
9371 // Fill the details.
9372 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
9373 details->set(kThreadDetailsThreadIdIndex,
9374 Smi::FromInt(ThreadManager::CurrentId()));
9375 } else {
9376 // Find the thread with the requested index.
9377 int n = 1;
9378 ThreadState* thread = ThreadState::FirstInUse();
9379 while (index != n && thread != NULL) {
9380 thread = thread->Next();
9381 n++;
9382 }
9383 if (thread == NULL) {
9384 return Heap::undefined_value();
9385 }
9386
9387 // Fill the details.
9388 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
9389 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
9390 }
9391
9392 // Convert to JS array and return.
9393 return *Factory::NewJSArrayWithElements(details);
9394}
9395
9396
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009397// Sets the disable break state
9398// args[0]: disable break state
lrn@chromium.org303ada72010-10-27 09:33:13 +00009399static MaybeObject* Runtime_SetDisableBreak(Arguments args) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009400 HandleScope scope;
9401 ASSERT(args.length() == 1);
9402 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
9403 Debug::set_disable_break(disable_break);
9404 return Heap::undefined_value();
9405}
9406
9407
lrn@chromium.org303ada72010-10-27 09:33:13 +00009408static MaybeObject* Runtime_GetBreakLocations(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009409 HandleScope scope;
9410 ASSERT(args.length() == 1);
9411
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009412 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9413 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009414 // Find the number of break points
9415 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
9416 if (break_locations->IsUndefined()) return Heap::undefined_value();
9417 // Return array as JS array
9418 return *Factory::NewJSArrayWithElements(
9419 Handle<FixedArray>::cast(break_locations));
9420}
9421
9422
9423// Set a break point in a function
9424// args[0]: function
9425// args[1]: number: break source position (within the function source)
9426// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009427static MaybeObject* Runtime_SetFunctionBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009428 HandleScope scope;
9429 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009430 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9431 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009432 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9433 RUNTIME_ASSERT(source_position >= 0);
9434 Handle<Object> break_point_object_arg = args.at<Object>(2);
9435
9436 // Set break point.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009437 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009438
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009439 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009440}
9441
9442
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009443Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
9444 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009445 // Iterate the heap looking for SharedFunctionInfo generated from the
9446 // script. The inner most SharedFunctionInfo containing the source position
9447 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009448 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009449 // which is found is not compiled it is compiled and the heap is iterated
9450 // again as the compilation might create inner functions from the newly
9451 // compiled function and the actual requested break point might be in one of
9452 // these functions.
9453 bool done = false;
9454 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00009455 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009456 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009457 while (!done) {
9458 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009459 for (HeapObject* obj = iterator.next();
9460 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009461 if (obj->IsSharedFunctionInfo()) {
9462 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
9463 if (shared->script() == *script) {
9464 // If the SharedFunctionInfo found has the requested script data and
9465 // contains the source position it is a candidate.
9466 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00009467 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009468 start_position = shared->start_position();
9469 }
9470 if (start_position <= position &&
9471 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00009472 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009473 // candidate this is the new candidate.
9474 if (target.is_null()) {
9475 target_start_position = start_position;
9476 target = shared;
9477 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00009478 if (target_start_position == start_position &&
9479 shared->end_position() == target->end_position()) {
9480 // If a top-level function contain only one function
9481 // declartion the source for the top-level and the function is
9482 // the same. In that case prefer the non top-level function.
9483 if (!shared->is_toplevel()) {
9484 target_start_position = start_position;
9485 target = shared;
9486 }
9487 } else if (target_start_position <= start_position &&
9488 shared->end_position() <= target->end_position()) {
9489 // This containment check includes equality as a function inside
9490 // a top-level function can share either start or end position
9491 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009492 target_start_position = start_position;
9493 target = shared;
9494 }
9495 }
9496 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009497 }
9498 }
9499 }
9500
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009501 if (target.is_null()) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009502 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009503 }
9504
9505 // If the candidate found is compiled we are done. NOTE: when lazy
9506 // compilation of inner functions is introduced some additional checking
9507 // needs to be done here to compile inner functions.
9508 done = target->is_compiled();
9509 if (!done) {
9510 // If the candidate is not compiled compile it to reveal any inner
9511 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009512 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009513 }
9514 }
9515
9516 return *target;
9517}
9518
9519
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009520// Changes the state of a break point in a script and returns source position
9521// where break point was set. NOTE: Regarding performance see the NOTE for
9522// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009523// args[0]: script to set break point in
9524// args[1]: number: break source position (within the script source)
9525// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009526static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009527 HandleScope scope;
9528 ASSERT(args.length() == 3);
9529 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
9530 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9531 RUNTIME_ASSERT(source_position >= 0);
9532 Handle<Object> break_point_object_arg = args.at<Object>(2);
9533
9534 // Get the script from the script wrapper.
9535 RUNTIME_ASSERT(wrapper->value()->IsScript());
9536 Handle<Script> script(Script::cast(wrapper->value()));
9537
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009538 Object* result = Runtime::FindSharedFunctionInfoInScript(
9539 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009540 if (!result->IsUndefined()) {
9541 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
9542 // Find position within function. The script position might be before the
9543 // source position of the first function.
9544 int position;
9545 if (shared->start_position() > source_position) {
9546 position = 0;
9547 } else {
9548 position = source_position - shared->start_position();
9549 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009550 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
9551 position += shared->start_position();
9552 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009553 }
9554 return Heap::undefined_value();
9555}
9556
9557
9558// Clear a break point
9559// args[0]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009560static MaybeObject* Runtime_ClearBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009561 HandleScope scope;
9562 ASSERT(args.length() == 1);
9563 Handle<Object> break_point_object_arg = args.at<Object>(0);
9564
9565 // Clear break point.
9566 Debug::ClearBreakPoint(break_point_object_arg);
9567
9568 return Heap::undefined_value();
9569}
9570
9571
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009572// Change the state of break on exceptions.
9573// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
9574// args[1]: Boolean indicating on/off.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009575static MaybeObject* Runtime_ChangeBreakOnException(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009576 HandleScope scope;
9577 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009578 RUNTIME_ASSERT(args[0]->IsNumber());
9579 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009580
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009581 // If the number doesn't match an enum value, the ChangeBreakOnException
9582 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009583 ExceptionBreakType type =
9584 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009585 // Update break point state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009586 Debug::ChangeBreakOnException(type, enable);
9587 return Heap::undefined_value();
9588}
9589
9590
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009591// Returns the state of break on exceptions
9592// args[0]: boolean indicating uncaught exceptions
lrn@chromium.org303ada72010-10-27 09:33:13 +00009593static MaybeObject* Runtime_IsBreakOnException(Arguments args) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009594 HandleScope scope;
9595 ASSERT(args.length() == 1);
9596 RUNTIME_ASSERT(args[0]->IsNumber());
9597
9598 ExceptionBreakType type =
9599 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
9600 bool result = Debug::IsBreakOnException(type);
9601 return Smi::FromInt(result);
9602}
9603
9604
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009605// Prepare for stepping
9606// args[0]: break id for checking execution state
9607// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +00009608// args[2]: number of times to perform the step, for step out it is the number
9609// of frames to step down.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009610static MaybeObject* Runtime_PrepareStep(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009611 HandleScope scope;
9612 ASSERT(args.length() == 3);
9613 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009614 Object* check;
9615 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9616 if (!maybe_check->ToObject(&check)) return maybe_check;
9617 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009618 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
9619 return Top::Throw(Heap::illegal_argument_symbol());
9620 }
9621
9622 // Get the step action and check validity.
9623 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
9624 if (step_action != StepIn &&
9625 step_action != StepNext &&
9626 step_action != StepOut &&
9627 step_action != StepInMin &&
9628 step_action != StepMin) {
9629 return Top::Throw(Heap::illegal_argument_symbol());
9630 }
9631
9632 // Get the number of steps.
9633 int step_count = NumberToInt32(args[2]);
9634 if (step_count < 1) {
9635 return Top::Throw(Heap::illegal_argument_symbol());
9636 }
9637
ager@chromium.orga1645e22009-09-09 19:27:10 +00009638 // Clear all current stepping setup.
9639 Debug::ClearStepping();
9640
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009641 // Prepare step.
9642 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
9643 return Heap::undefined_value();
9644}
9645
9646
9647// Clear all stepping set by PrepareStep.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009648static MaybeObject* Runtime_ClearStepping(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009649 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009650 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009651 Debug::ClearStepping();
9652 return Heap::undefined_value();
9653}
9654
9655
9656// Creates a copy of the with context chain. The copy of the context chain is
9657// is linked to the function context supplied.
9658static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
9659 Handle<Context> function_context) {
9660 // At the bottom of the chain. Return the function context to link to.
9661 if (context_chain->is_function_context()) {
9662 return function_context;
9663 }
9664
9665 // Recursively copy the with contexts.
9666 Handle<Context> previous(context_chain->previous());
9667 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009668 Handle<Context> context = CopyWithContextChain(function_context, previous);
9669 return Factory::NewWithContext(context,
9670 extension,
9671 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009672}
9673
9674
9675// Helper function to find or create the arguments object for
9676// Runtime_DebugEvaluate.
9677static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
9678 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009679 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009680 const ScopeInfo<>* sinfo,
9681 Handle<Context> function_context) {
9682 // Try to find the value of 'arguments' to pass as parameter. If it is not
9683 // found (that is the debugged function does not reference 'arguments' and
9684 // does not support eval) then create an 'arguments' object.
9685 int index;
9686 if (sinfo->number_of_stack_slots() > 0) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009687 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009688 if (index != -1) {
9689 return Handle<Object>(frame->GetExpression(index));
9690 }
9691 }
9692
9693 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009694 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009695 if (index != -1) {
9696 return Handle<Object>(function_context->get(index));
9697 }
9698 }
9699
9700 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009701 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
9702 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009703
9704 AssertNoAllocation no_gc;
9705 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009706 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009707 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009708 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009709 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009710 return arguments;
9711}
9712
9713
9714// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +00009715// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009716// extension part has all the parameters and locals of the function on the
9717// stack frame. A function which calls eval with the code to evaluate is then
9718// compiled in this context and called in this context. As this context
9719// replaces the context of the function on the stack frame a new (empty)
9720// function is created as well to be used as the closure for the context.
9721// This function and the context acts as replacements for the function on the
9722// stack frame presenting the same view of the values of parameters and
9723// local variables as if the piece of JavaScript was evaluated at the point
9724// where the function on the stack frame is currently stopped.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009725static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009726 HandleScope scope;
9727
9728 // Check the execution state and decode arguments frame and source to be
9729 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009730 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009731 Object* check_result;
9732 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9733 if (!maybe_check_result->ToObject(&check_result)) {
9734 return maybe_check_result;
9735 }
9736 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009737 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9738 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009739 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009740 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009741
9742 // Handle the processing of break.
9743 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009744
9745 // Get the frame where the debugging is performed.
9746 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9747 JavaScriptFrameIterator it(id);
9748 JavaScriptFrame* frame = it.frame();
9749 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009750 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009751 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009752
9753 // Traverse the saved contexts chain to find the active context for the
9754 // selected frame.
9755 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009756 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009757 save = save->prev();
9758 }
9759 ASSERT(save != NULL);
9760 SaveContext savex;
9761 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009762
9763 // Create the (empty) function replacing the function on the stack frame for
9764 // the purpose of evaluating in the context created below. It is important
9765 // that this function does not describe any parameters and local variables
9766 // in the context. If it does then this will cause problems with the lookup
9767 // in Context::Lookup, where context slots for parameters and local variables
9768 // are looked at before the extension object.
9769 Handle<JSFunction> go_between =
9770 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
9771 go_between->set_context(function->context());
9772#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009773 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009774 ASSERT(go_between_sinfo.number_of_parameters() == 0);
9775 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
9776#endif
9777
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009778 // Materialize the content of the local scope into a JSObject.
9779 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009780
9781 // Allocate a new context for the debug evaluation and set the extension
9782 // object build.
9783 Handle<Context> context =
9784 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009785 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009786 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009787 Handle<Context> frame_context(Context::cast(frame->context()));
9788 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009789 context = CopyWithContextChain(frame_context, context);
9790
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009791 if (additional_context->IsJSObject()) {
9792 context = Factory::NewWithContext(context,
9793 Handle<JSObject>::cast(additional_context), false);
9794 }
9795
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009796 // Wrap the evaluation statement in a new function compiled in the newly
9797 // created context. The function has one parameter which has to be called
9798 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +00009799 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009800 // function(arguments,__source__) {return eval(__source__);}
9801 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009802 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009803 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009804 Handle<String> function_source =
9805 Factory::NewStringFromAscii(Vector<const char>(source_str,
9806 source_str_length));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009807 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +00009808 Compiler::CompileEval(function_source,
9809 context,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009810 context->IsGlobalContext());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009811 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009812 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009813 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009814
9815 // Invoke the result of the compilation to get the evaluation function.
9816 bool has_pending_exception;
9817 Handle<Object> receiver(frame->receiver());
9818 Handle<Object> evaluation_function =
9819 Execution::Call(compiled_function, receiver, 0, NULL,
9820 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009821 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009822
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009823 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
9824 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009825
9826 // Invoke the evaluation function and return the result.
9827 const int argc = 2;
9828 Object** argv[argc] = { arguments.location(),
9829 Handle<Object>::cast(source).location() };
9830 Handle<Object> result =
9831 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
9832 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009833 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009834
9835 // Skip the global proxy as it has no properties and always delegates to the
9836 // real global object.
9837 if (result->IsJSGlobalProxy()) {
9838 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
9839 }
9840
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009841 return *result;
9842}
9843
9844
lrn@chromium.org303ada72010-10-27 09:33:13 +00009845static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009846 HandleScope scope;
9847
9848 // Check the execution state and decode arguments frame and source to be
9849 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009850 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009851 Object* check_result;
9852 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9853 if (!maybe_check_result->ToObject(&check_result)) {
9854 return maybe_check_result;
9855 }
9856 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009857 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009858 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009859 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009860
9861 // Handle the processing of break.
9862 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009863
9864 // Enter the top context from before the debugger was invoked.
9865 SaveContext save;
9866 SaveContext* top = &save;
9867 while (top != NULL && *top->context() == *Debug::debug_context()) {
9868 top = top->prev();
9869 }
9870 if (top != NULL) {
9871 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009872 }
9873
9874 // Get the global context now set to the top context from before the
9875 // debugger was invoked.
9876 Handle<Context> context = Top::global_context();
9877
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009878 bool is_global = true;
9879
9880 if (additional_context->IsJSObject()) {
9881 // Create a function context first, than put 'with' context on top of it.
9882 Handle<JSFunction> go_between = Factory::NewFunction(
9883 Factory::empty_string(), Factory::undefined_value());
9884 go_between->set_context(*context);
9885 context =
9886 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
9887 context->set_extension(JSObject::cast(*additional_context));
9888 is_global = false;
9889 }
9890
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009891 // Compile the source to be evaluated.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009892 Handle<SharedFunctionInfo> shared =
9893 Compiler::CompileEval(source,
9894 context,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009895 is_global);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009896 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009897 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009898 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
9899 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009900
9901 // Invoke the result of the compilation to get the evaluation function.
9902 bool has_pending_exception;
9903 Handle<Object> receiver = Top::global();
9904 Handle<Object> result =
9905 Execution::Call(compiled_function, receiver, 0, NULL,
9906 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009907 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009908 return *result;
9909}
9910
9911
lrn@chromium.org303ada72010-10-27 09:33:13 +00009912static MaybeObject* Runtime_DebugGetLoadedScripts(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009913 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009914 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009915
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009916 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009917 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009918
9919 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009920 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00009921 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
9922 // Get the script wrapper in a local handle before calling GetScriptWrapper,
9923 // because using
9924 // instances->set(i, *GetScriptWrapper(script))
9925 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
9926 // already have deferenced the instances handle.
9927 Handle<JSValue> wrapper = GetScriptWrapper(script);
9928 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009929 }
9930
9931 // Return result as a JS array.
9932 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
9933 Handle<JSArray>::cast(result)->SetContent(*instances);
9934 return *result;
9935}
9936
9937
9938// Helper function used by Runtime_DebugReferencedBy below.
9939static int DebugReferencedBy(JSObject* target,
9940 Object* instance_filter, int max_references,
9941 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009942 JSFunction* arguments_function) {
9943 NoHandleAllocation ha;
9944 AssertNoAllocation no_alloc;
9945
9946 // Iterate the heap.
9947 int count = 0;
9948 JSObject* last = NULL;
9949 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009950 HeapObject* heap_obj = NULL;
9951 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009952 (max_references == 0 || count < max_references)) {
9953 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009954 if (heap_obj->IsJSObject()) {
9955 // Skip context extension objects and argument arrays as these are
9956 // checked in the context of functions using them.
9957 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009958 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009959 obj->map()->constructor() == arguments_function) {
9960 continue;
9961 }
9962
9963 // Check if the JS object has a reference to the object looked for.
9964 if (obj->ReferencesObject(target)) {
9965 // Check instance filter if supplied. This is normally used to avoid
9966 // references from mirror objects (see Runtime_IsInPrototypeChain).
9967 if (!instance_filter->IsUndefined()) {
9968 Object* V = obj;
9969 while (true) {
9970 Object* prototype = V->GetPrototype();
9971 if (prototype->IsNull()) {
9972 break;
9973 }
9974 if (instance_filter == prototype) {
9975 obj = NULL; // Don't add this object.
9976 break;
9977 }
9978 V = prototype;
9979 }
9980 }
9981
9982 if (obj != NULL) {
9983 // Valid reference found add to instance array if supplied an update
9984 // count.
9985 if (instances != NULL && count < instances_size) {
9986 instances->set(count, obj);
9987 }
9988 last = obj;
9989 count++;
9990 }
9991 }
9992 }
9993 }
9994
9995 // Check for circular reference only. This can happen when the object is only
9996 // referenced from mirrors and has a circular reference in which case the
9997 // object is not really alive and would have been garbage collected if not
9998 // referenced from the mirror.
9999 if (count == 1 && last == target) {
10000 count = 0;
10001 }
10002
10003 // Return the number of referencing objects found.
10004 return count;
10005}
10006
10007
10008// Scan the heap for objects with direct references to an object
10009// args[0]: the object to find references to
10010// args[1]: constructor function for instances to exclude (Mirror)
10011// args[2]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010012static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010013 ASSERT(args.length() == 3);
10014
10015 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010016 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010017
10018 // Check parameters.
10019 CONVERT_CHECKED(JSObject, target, args[0]);
10020 Object* instance_filter = args[1];
10021 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
10022 instance_filter->IsJSObject());
10023 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
10024 RUNTIME_ASSERT(max_references >= 0);
10025
10026 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010027 JSObject* arguments_boilerplate =
10028 Top::context()->global_context()->arguments_boilerplate();
10029 JSFunction* arguments_function =
10030 JSFunction::cast(arguments_boilerplate->map()->constructor());
10031
10032 // Get the number of referencing objects.
10033 int count;
10034 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010035 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010036
10037 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010038 Object* object;
10039 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10040 if (!maybe_object->ToObject(&object)) return maybe_object;
10041 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010042 FixedArray* instances = FixedArray::cast(object);
10043
10044 // Fill the referencing objects.
10045 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010046 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010047
10048 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010049 Object* result;
10050 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10051 Top::context()->global_context()->array_function());
10052 if (!maybe_result->ToObject(&result)) return maybe_result;
10053 }
10054 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010055 return result;
10056}
10057
10058
10059// Helper function used by Runtime_DebugConstructedBy below.
10060static int DebugConstructedBy(JSFunction* constructor, int max_references,
10061 FixedArray* instances, int instances_size) {
10062 AssertNoAllocation no_alloc;
10063
10064 // Iterate the heap.
10065 int count = 0;
10066 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010067 HeapObject* heap_obj = NULL;
10068 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010069 (max_references == 0 || count < max_references)) {
10070 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010071 if (heap_obj->IsJSObject()) {
10072 JSObject* obj = JSObject::cast(heap_obj);
10073 if (obj->map()->constructor() == constructor) {
10074 // Valid reference found add to instance array if supplied an update
10075 // count.
10076 if (instances != NULL && count < instances_size) {
10077 instances->set(count, obj);
10078 }
10079 count++;
10080 }
10081 }
10082 }
10083
10084 // Return the number of referencing objects found.
10085 return count;
10086}
10087
10088
10089// Scan the heap for objects constructed by a specific function.
10090// args[0]: the constructor to find instances of
10091// args[1]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010092static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010093 ASSERT(args.length() == 2);
10094
10095 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010096 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010097
10098 // Check parameters.
10099 CONVERT_CHECKED(JSFunction, constructor, args[0]);
10100 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
10101 RUNTIME_ASSERT(max_references >= 0);
10102
10103 // Get the number of referencing objects.
10104 int count;
10105 count = DebugConstructedBy(constructor, max_references, NULL, 0);
10106
10107 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010108 Object* object;
10109 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10110 if (!maybe_object->ToObject(&object)) return maybe_object;
10111 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010112 FixedArray* instances = FixedArray::cast(object);
10113
10114 // Fill the referencing objects.
10115 count = DebugConstructedBy(constructor, max_references, instances, count);
10116
10117 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010118 Object* result;
10119 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10120 Top::context()->global_context()->array_function());
10121 if (!maybe_result->ToObject(&result)) return maybe_result;
10122 }
10123 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010124 return result;
10125}
10126
10127
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010128// Find the effective prototype object as returned by __proto__.
10129// args[0]: the object to find the prototype for.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010130static MaybeObject* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010131 ASSERT(args.length() == 1);
10132
10133 CONVERT_CHECKED(JSObject, obj, args[0]);
10134
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010135 // Use the __proto__ accessor.
10136 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010137}
10138
10139
lrn@chromium.org303ada72010-10-27 09:33:13 +000010140static MaybeObject* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010141 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010142 CPU::DebugBreak();
10143 return Heap::undefined_value();
10144}
10145
10146
lrn@chromium.org303ada72010-10-27 09:33:13 +000010147static MaybeObject* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010148#ifdef DEBUG
10149 HandleScope scope;
10150 ASSERT(args.length() == 1);
10151 // Get the function and make sure it is compiled.
10152 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010153 Handle<SharedFunctionInfo> shared(func->shared());
10154 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010155 return Failure::Exception();
10156 }
10157 func->code()->PrintLn();
10158#endif // DEBUG
10159 return Heap::undefined_value();
10160}
ager@chromium.org9085a012009-05-11 19:22:57 +000010161
10162
lrn@chromium.org303ada72010-10-27 09:33:13 +000010163static MaybeObject* Runtime_DebugDisassembleConstructor(Arguments args) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010164#ifdef DEBUG
10165 HandleScope scope;
10166 ASSERT(args.length() == 1);
10167 // Get the function and make sure it is compiled.
10168 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010169 Handle<SharedFunctionInfo> shared(func->shared());
10170 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010171 return Failure::Exception();
10172 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010173 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010174#endif // DEBUG
10175 return Heap::undefined_value();
10176}
10177
10178
lrn@chromium.org303ada72010-10-27 09:33:13 +000010179static MaybeObject* Runtime_FunctionGetInferredName(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +000010180 NoHandleAllocation ha;
10181 ASSERT(args.length() == 1);
10182
10183 CONVERT_CHECKED(JSFunction, f, args[0]);
10184 return f->shared()->inferred_name();
10185}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010186
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010187
10188static int FindSharedFunctionInfosForScript(Script* script,
10189 FixedArray* buffer) {
10190 AssertNoAllocation no_allocations;
10191
10192 int counter = 0;
10193 int buffer_size = buffer->length();
10194 HeapIterator iterator;
10195 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
10196 ASSERT(obj != NULL);
10197 if (!obj->IsSharedFunctionInfo()) {
10198 continue;
10199 }
10200 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
10201 if (shared->script() != script) {
10202 continue;
10203 }
10204 if (counter < buffer_size) {
10205 buffer->set(counter, shared);
10206 }
10207 counter++;
10208 }
10209 return counter;
10210}
10211
10212// For a script finds all SharedFunctionInfo's in the heap that points
10213// to this script. Returns JSArray of SharedFunctionInfo wrapped
10214// in OpaqueReferences.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010215static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010216 Arguments args) {
10217 ASSERT(args.length() == 1);
10218 HandleScope scope;
10219 CONVERT_CHECKED(JSValue, script_value, args[0]);
10220
10221 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
10222
10223 const int kBufferSize = 32;
10224
10225 Handle<FixedArray> array;
10226 array = Factory::NewFixedArray(kBufferSize);
10227 int number = FindSharedFunctionInfosForScript(*script, *array);
10228 if (number > kBufferSize) {
10229 array = Factory::NewFixedArray(number);
10230 FindSharedFunctionInfosForScript(*script, *array);
10231 }
10232
10233 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
10234 result->set_length(Smi::FromInt(number));
10235
10236 LiveEdit::WrapSharedFunctionInfos(result);
10237
10238 return *result;
10239}
10240
10241// For a script calculates compilation information about all its functions.
10242// The script source is explicitly specified by the second argument.
10243// The source of the actual script is not used, however it is important that
10244// all generated code keeps references to this particular instance of script.
10245// Returns a JSArray of compilation infos. The array is ordered so that
10246// each function with all its descendant is always stored in a continues range
10247// with the function itself going first. The root function is a script function.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010248static MaybeObject* Runtime_LiveEditGatherCompileInfo(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010249 ASSERT(args.length() == 2);
10250 HandleScope scope;
10251 CONVERT_CHECKED(JSValue, script, args[0]);
10252 CONVERT_ARG_CHECKED(String, source, 1);
10253 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
10254
10255 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
10256
10257 if (Top::has_pending_exception()) {
10258 return Failure::Exception();
10259 }
10260
10261 return result;
10262}
10263
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010264// Changes the source of the script to a new_source.
10265// If old_script_name is provided (i.e. is a String), also creates a copy of
10266// the script with its original source and sends notification to debugger.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010267static MaybeObject* Runtime_LiveEditReplaceScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010268 ASSERT(args.length() == 3);
10269 HandleScope scope;
10270 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
10271 CONVERT_ARG_CHECKED(String, new_source, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010272 Handle<Object> old_script_name(args[2]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010273
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010274 CONVERT_CHECKED(Script, original_script_pointer,
10275 original_script_value->value());
10276 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010277
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010278 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
10279 new_source,
10280 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010281
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010282 if (old_script->IsScript()) {
10283 Handle<Script> script_handle(Script::cast(old_script));
10284 return *(GetScriptWrapper(script_handle));
10285 } else {
10286 return Heap::null_value();
10287 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010288}
10289
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010290
10291static MaybeObject* Runtime_LiveEditFunctionSourceUpdated(Arguments args) {
10292 ASSERT(args.length() == 1);
10293 HandleScope scope;
10294 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
10295 return LiveEdit::FunctionSourceUpdated(shared_info);
10296}
10297
10298
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010299// Replaces code of SharedFunctionInfo with a new one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010300static MaybeObject* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010301 ASSERT(args.length() == 2);
10302 HandleScope scope;
10303 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
10304 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
10305
ager@chromium.orgac091b72010-05-05 07:34:42 +000010306 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010307}
10308
10309// Connects SharedFunctionInfo to another script.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010310static MaybeObject* Runtime_LiveEditFunctionSetScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010311 ASSERT(args.length() == 2);
10312 HandleScope scope;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010313 Handle<Object> function_object(args[0]);
10314 Handle<Object> script_object(args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010315
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010316 if (function_object->IsJSValue()) {
10317 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
10318 if (script_object->IsJSValue()) {
10319 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
10320 script_object = Handle<Object>(script);
10321 }
10322
10323 LiveEdit::SetFunctionScript(function_wrapper, script_object);
10324 } else {
10325 // Just ignore this. We may not have a SharedFunctionInfo for some functions
10326 // and we check it in this function.
10327 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010328
10329 return Heap::undefined_value();
10330}
10331
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010332
10333// In a code of a parent function replaces original function as embedded object
10334// with a substitution one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010335static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010336 ASSERT(args.length() == 3);
10337 HandleScope scope;
10338
10339 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
10340 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
10341 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
10342
10343 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
10344 subst_wrapper);
10345
10346 return Heap::undefined_value();
10347}
10348
10349
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010350// Updates positions of a shared function info (first parameter) according
10351// to script source change. Text change is described in second parameter as
10352// array of groups of 3 numbers:
10353// (change_begin, change_end, change_end_new_position).
10354// Each group describes a change in text; groups are sorted by change_begin.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010355static MaybeObject* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010356 ASSERT(args.length() == 2);
10357 HandleScope scope;
10358 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
10359 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
10360
ager@chromium.orgac091b72010-05-05 07:34:42 +000010361 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010362}
10363
10364
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010365// For array of SharedFunctionInfo's (each wrapped in JSValue)
10366// checks that none of them have activations on stacks (of any thread).
10367// Returns array of the same length with corresponding results of
10368// LiveEdit::FunctionPatchabilityStatus type.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010369static MaybeObject* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010370 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010371 HandleScope scope;
10372 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000010373 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010374
ager@chromium.org357bf652010-04-12 11:30:10 +000010375 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010376}
10377
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010378// Compares 2 strings line-by-line, then token-wise and returns diff in form
10379// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
10380// of diff chunks.
10381static MaybeObject* Runtime_LiveEditCompareStrings(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010382 ASSERT(args.length() == 2);
10383 HandleScope scope;
10384 CONVERT_ARG_CHECKED(String, s1, 0);
10385 CONVERT_ARG_CHECKED(String, s2, 1);
10386
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010387 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010388}
10389
10390
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010391
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010392// A testing entry. Returns statement position which is the closest to
10393// source_position.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010394static MaybeObject* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010395 ASSERT(args.length() == 2);
10396 HandleScope scope;
10397 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10398 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10399
10400 Handle<Code> code(function->code());
10401
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010402 if (code->kind() != Code::FUNCTION &&
10403 code->kind() != Code::OPTIMIZED_FUNCTION) {
10404 return Heap::undefined_value();
10405 }
10406
10407 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010408 int closest_pc = 0;
10409 int distance = kMaxInt;
10410 while (!it.done()) {
10411 int statement_position = static_cast<int>(it.rinfo()->data());
10412 // Check if this break point is closer that what was previously found.
10413 if (source_position <= statement_position &&
10414 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000010415 closest_pc =
10416 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010417 distance = statement_position - source_position;
10418 // Check whether we can't get any closer.
10419 if (distance == 0) break;
10420 }
10421 it.next();
10422 }
10423
10424 return Smi::FromInt(closest_pc);
10425}
10426
10427
ager@chromium.org357bf652010-04-12 11:30:10 +000010428// Calls specified function with or without entering the debugger.
10429// This is used in unit tests to run code as if debugger is entered or simply
10430// to have a stack with C++ frame in the middle.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010431static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010432 ASSERT(args.length() == 2);
10433 HandleScope scope;
10434 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10435 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
10436
10437 Handle<Object> result;
10438 bool pending_exception;
10439 {
10440 if (without_debugger) {
10441 result = Execution::Call(function, Top::global(), 0, NULL,
10442 &pending_exception);
10443 } else {
10444 EnterDebugger enter_debugger;
10445 result = Execution::Call(function, Top::global(), 0, NULL,
10446 &pending_exception);
10447 }
10448 }
10449 if (!pending_exception) {
10450 return *result;
10451 } else {
10452 return Failure::Exception();
10453 }
10454}
10455
10456
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010457// Sets a v8 flag.
10458static MaybeObject* Runtime_SetFlags(Arguments args) {
10459 CONVERT_CHECKED(String, arg, args[0]);
10460 SmartPointer<char> flags =
10461 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
10462 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
10463 return Heap::undefined_value();
10464}
10465
10466
10467// Performs a GC.
10468// Presently, it only does a full GC.
10469static MaybeObject* Runtime_CollectGarbage(Arguments args) {
10470 Heap::CollectAllGarbage(true);
10471 return Heap::undefined_value();
10472}
10473
10474
10475// Gets the current heap usage.
10476static MaybeObject* Runtime_GetHeapUsage(Arguments args) {
10477 int usage = static_cast<int>(Heap::SizeOfObjects());
10478 if (!Smi::IsValid(usage)) {
10479 return *Factory::NewNumberFromInt(usage);
10480 }
10481 return Smi::FromInt(usage);
10482}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010483#endif // ENABLE_DEBUGGER_SUPPORT
10484
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010485
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000010486#ifdef ENABLE_LOGGING_AND_PROFILING
lrn@chromium.org303ada72010-10-27 09:33:13 +000010487static MaybeObject* Runtime_ProfilerResume(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010488 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010489 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010490
10491 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010492 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10493 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010494 return Heap::undefined_value();
10495}
10496
10497
lrn@chromium.org303ada72010-10-27 09:33:13 +000010498static MaybeObject* Runtime_ProfilerPause(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010499 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010500 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010501
10502 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010503 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10504 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010505 return Heap::undefined_value();
10506}
10507
10508#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010509
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010510// Finds the script object from the script data. NOTE: This operation uses
10511// heap traversal to find the function generated for the source position
10512// for the requested break point. For lazily compiled functions several heap
10513// traversals might be required rendering this operation as a rather slow
10514// operation. However for setting break points which is normally done through
10515// some kind of user interaction the performance is not crucial.
10516static Handle<Object> Runtime_GetScriptFromScriptName(
10517 Handle<String> script_name) {
10518 // Scan the heap for Script objects to find the script with the requested
10519 // script data.
10520 Handle<Script> script;
10521 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010522 HeapObject* obj = NULL;
10523 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010524 // If a script is found check if it has the script data requested.
10525 if (obj->IsScript()) {
10526 if (Script::cast(obj)->name()->IsString()) {
10527 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
10528 script = Handle<Script>(Script::cast(obj));
10529 }
10530 }
10531 }
10532 }
10533
10534 // If no script with the requested script data is found return undefined.
10535 if (script.is_null()) return Factory::undefined_value();
10536
10537 // Return the script found.
10538 return GetScriptWrapper(script);
10539}
10540
10541
10542// Get the script object from script data. NOTE: Regarding performance
10543// see the NOTE for GetScriptFromScriptData.
10544// args[0]: script data for the script to find the source for
lrn@chromium.org303ada72010-10-27 09:33:13 +000010545static MaybeObject* Runtime_GetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010546 HandleScope scope;
10547
10548 ASSERT(args.length() == 1);
10549
10550 CONVERT_CHECKED(String, script_name, args[0]);
10551
10552 // Find the requested script.
10553 Handle<Object> result =
10554 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
10555 return *result;
10556}
10557
10558
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010559// Determines whether the given stack frame should be displayed in
10560// a stack trace. The caller is the error constructor that asked
10561// for the stack trace to be collected. The first time a construct
10562// call to this function is encountered it is skipped. The seen_caller
10563// in/out parameter is used to remember if the caller has been seen
10564// yet.
10565static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
10566 bool* seen_caller) {
10567 // Only display JS frames.
10568 if (!raw_frame->is_java_script())
10569 return false;
10570 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
10571 Object* raw_fun = frame->function();
10572 // Not sure when this can happen but skip it just in case.
10573 if (!raw_fun->IsJSFunction())
10574 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010575 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010576 *seen_caller = true;
10577 return false;
10578 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010579 // Skip all frames until we've seen the caller. Also, skip the most
10580 // obvious builtin calls. Some builtin calls (such as Number.ADD
10581 // which is invoked using 'call') are very difficult to recognize
10582 // so we're leaving them in for now.
10583 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010584}
10585
10586
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010587// Collect the raw data for a stack trace. Returns an array of 4
10588// element segments each containing a receiver, function, code and
10589// native code offset.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010590static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010591 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010592 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010593 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
10594
10595 HandleScope scope;
10596
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000010597 limit = Max(limit, 0); // Ensure that limit is not negative.
10598 int initial_size = Min(limit, 10);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010599 Handle<JSArray> result = Factory::NewJSArray(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010600
10601 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010602 // If the caller parameter is a function we skip frames until we're
10603 // under it before starting to collect.
10604 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010605 int cursor = 0;
10606 int frames_seen = 0;
10607 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010608 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010609 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010610 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010611 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010612 List<FrameSummary> frames(3); // Max 2 levels of inlining.
10613 frame->Summarize(&frames);
10614 for (int i = frames.length() - 1; i >= 0; i--) {
10615 Handle<Object> recv = frames[i].receiver();
10616 Handle<JSFunction> fun = frames[i].function();
10617 Handle<Code> code = frames[i].code();
10618 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
10619 FixedArray* elements = FixedArray::cast(result->elements());
10620 if (cursor + 3 < elements->length()) {
10621 elements->set(cursor++, *recv);
10622 elements->set(cursor++, *fun);
10623 elements->set(cursor++, *code);
10624 elements->set(cursor++, *offset);
10625 } else {
10626 SetElement(result, cursor++, recv);
10627 SetElement(result, cursor++, fun);
10628 SetElement(result, cursor++, code);
10629 SetElement(result, cursor++, offset);
10630 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010631 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010632 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010633 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010634 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010635
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010636 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010637 return *result;
10638}
10639
10640
ager@chromium.org3811b432009-10-28 14:53:37 +000010641// Returns V8 version as a string.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010642static MaybeObject* Runtime_GetV8Version(Arguments args) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010643 ASSERT_EQ(args.length(), 0);
10644
10645 NoHandleAllocation ha;
10646
10647 const char* version_string = v8::V8::GetVersion();
10648
10649 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
10650}
10651
10652
lrn@chromium.org303ada72010-10-27 09:33:13 +000010653static MaybeObject* Runtime_Abort(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010654 ASSERT(args.length() == 2);
10655 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
10656 Smi::cast(args[1])->value());
10657 Top::PrintStack();
10658 OS::Abort();
10659 UNREACHABLE();
10660 return NULL;
10661}
10662
10663
lrn@chromium.org303ada72010-10-27 09:33:13 +000010664static MaybeObject* Runtime_GetFromCache(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010665 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010666 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010667 Object* key = args[1];
10668
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010669 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010670 Object* o = cache->get(finger_index);
10671 if (o == key) {
10672 // The fastest case: hit the same place again.
10673 return cache->get(finger_index + 1);
10674 }
10675
10676 for (int i = finger_index - 2;
10677 i >= JSFunctionResultCache::kEntriesIndex;
10678 i -= 2) {
10679 o = cache->get(i);
10680 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010681 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010682 return cache->get(i + 1);
10683 }
10684 }
10685
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010686 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010687 ASSERT(size <= cache->length());
10688
10689 for (int i = size - 2; i > finger_index; i -= 2) {
10690 o = cache->get(i);
10691 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010692 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010693 return cache->get(i + 1);
10694 }
10695 }
10696
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010697 // There is no value in the cache. Invoke the function and cache result.
10698 HandleScope scope;
10699
10700 Handle<JSFunctionResultCache> cache_handle(cache);
10701 Handle<Object> key_handle(key);
10702 Handle<Object> value;
10703 {
10704 Handle<JSFunction> factory(JSFunction::cast(
10705 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
10706 // TODO(antonm): consider passing a receiver when constructing a cache.
10707 Handle<Object> receiver(Top::global_context()->global());
10708 // This handle is nor shared, nor used later, so it's safe.
10709 Object** argv[] = { key_handle.location() };
10710 bool pending_exception = false;
10711 value = Execution::Call(factory,
10712 receiver,
10713 1,
10714 argv,
10715 &pending_exception);
10716 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010717 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000010718
10719#ifdef DEBUG
10720 cache_handle->JSFunctionResultCacheVerify();
10721#endif
10722
10723 // Function invocation may have cleared the cache. Reread all the data.
10724 finger_index = cache_handle->finger_index();
10725 size = cache_handle->size();
10726
10727 // If we have spare room, put new data into it, otherwise evict post finger
10728 // entry which is likely to be the least recently used.
10729 int index = -1;
10730 if (size < cache_handle->length()) {
10731 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
10732 index = size;
10733 } else {
10734 index = finger_index + JSFunctionResultCache::kEntrySize;
10735 if (index == cache_handle->length()) {
10736 index = JSFunctionResultCache::kEntriesIndex;
10737 }
10738 }
10739
10740 ASSERT(index % 2 == 0);
10741 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
10742 ASSERT(index < cache_handle->length());
10743
10744 cache_handle->set(index, *key_handle);
10745 cache_handle->set(index + 1, *value);
10746 cache_handle->set_finger_index(index);
10747
10748#ifdef DEBUG
10749 cache_handle->JSFunctionResultCacheVerify();
10750#endif
10751
10752 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010753}
10754
kasper.lund44510672008-07-25 07:37:58 +000010755#ifdef DEBUG
10756// ListNatives is ONLY used by the fuzz-natives.js in debug mode
10757// Exclude the code in release mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010758static MaybeObject* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010759 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010760 HandleScope scope;
10761 Handle<JSArray> result = Factory::NewJSArray(0);
10762 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010763 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010764#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010765 { \
10766 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010767 Handle<String> name; \
10768 /* Inline runtime functions have an underscore in front of the name. */ \
10769 if (inline_runtime_functions) { \
10770 name = Factory::NewStringFromAscii( \
10771 Vector<const char>("_" #Name, StrLength("_" #Name))); \
10772 } else { \
10773 name = Factory::NewStringFromAscii( \
10774 Vector<const char>(#Name, StrLength(#Name))); \
10775 } \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010776 Handle<JSArray> pair = Factory::NewJSArray(0); \
10777 SetElement(pair, 0, name); \
10778 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
10779 SetElement(result, index++, pair); \
10780 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010781 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010782 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010783 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010784 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010785 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010786#undef ADD_ENTRY
10787 return *result;
10788}
kasper.lund44510672008-07-25 07:37:58 +000010789#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010790
10791
lrn@chromium.org303ada72010-10-27 09:33:13 +000010792static MaybeObject* Runtime_Log(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010793 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010794 CONVERT_CHECKED(String, format, args[0]);
10795 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010796 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010797 Logger::LogRuntime(chars, elms);
10798 return Heap::undefined_value();
10799}
10800
10801
lrn@chromium.org303ada72010-10-27 09:33:13 +000010802static MaybeObject* Runtime_IS_VAR(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010803 UNREACHABLE(); // implemented as macro in the parser
10804 return NULL;
10805}
10806
10807
10808// ----------------------------------------------------------------------------
10809// Implementation of Runtime
10810
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010811#define F(name, number_of_args, result_size) \
10812 { Runtime::k##name, Runtime::RUNTIME, #name, \
10813 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010814
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010815
10816#define I(name, number_of_args, result_size) \
10817 { Runtime::kInline##name, Runtime::INLINE, \
10818 "_" #name, NULL, number_of_args, result_size },
10819
10820Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010821 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010822 INLINE_FUNCTION_LIST(I)
10823 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010824};
10825
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010826
lrn@chromium.org303ada72010-10-27 09:33:13 +000010827MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010828 ASSERT(dictionary != NULL);
10829 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
10830 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010831 Object* name_symbol;
10832 { MaybeObject* maybe_name_symbol =
10833 Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
10834 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
10835 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010836 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010837 { MaybeObject* maybe_dictionary = string_dictionary->Add(
10838 String::cast(name_symbol),
10839 Smi::FromInt(i),
10840 PropertyDetails(NONE, NORMAL));
10841 if (!maybe_dictionary->ToObject(&dictionary)) {
10842 // Non-recoverable failure. Calling code must restart heap
10843 // initialization.
10844 return maybe_dictionary;
10845 }
10846 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010847 }
10848 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010849}
10850
10851
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010852Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
10853 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
10854 if (entry != kNotFound) {
10855 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
10856 int function_index = Smi::cast(smi_index)->value();
10857 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010858 }
10859 return NULL;
10860}
10861
10862
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010863Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
10864 return &(kIntrinsicFunctions[static_cast<int>(id)]);
10865}
10866
10867
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010868void Runtime::PerformGC(Object* result) {
10869 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010870 if (failure->IsRetryAfterGC()) {
10871 // Try to do a garbage collection; ignore it if it fails. The C
10872 // entry stub will throw an out-of-memory exception in that case.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000010873 Heap::CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010874 } else {
10875 // Handle last resort GC and make sure to allow future allocations
10876 // to grow the heap without causing GCs (if possible).
10877 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010878 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010879 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010880}
10881
10882
10883} } // namespace v8::internal