blob: efdb50879441560074dcc4cba8421387b8271386 [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()) {
333 // If key is a symbol it is not an array element.
334 Handle<String> name(String::cast(*key));
335 ASSERT(!name->AsArrayIndex(&element_index));
336 result = SetProperty(boilerplate, name, value, NONE);
337 } else if (key->ToArrayIndex(&element_index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000338 // Array index (uint32).
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000339 result = SetElement(boilerplate, element_index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000340 } else {
341 // Non-uint32 number.
342 ASSERT(key->IsNumber());
343 double num = key->Number();
344 char arr[100];
345 Vector<char> buffer(arr, ARRAY_SIZE(arr));
346 const char* str = DoubleToCString(num, buffer);
347 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000348 result = SetProperty(boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000349 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000350 // If setting the property on the boilerplate throws an
351 // exception, the exception is converted to an empty handle in
352 // the handle based operations. In that case, we need to
353 // convert back to an exception.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000354 if (result.is_null()) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355 }
356 }
357
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000358 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000359}
360
361
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000362static Handle<Object> CreateArrayLiteralBoilerplate(
363 Handle<FixedArray> literals,
364 Handle<FixedArray> elements) {
365 // Create the JSArray.
366 Handle<JSFunction> constructor(
367 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
368 Handle<Object> object = Factory::NewJSObject(constructor);
369
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000370 const bool is_cow = (elements->map() == Heap::fixed_cow_array_map());
371 Handle<FixedArray> copied_elements =
372 is_cow ? elements : Factory::CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000373
374 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000375 if (is_cow) {
376#ifdef DEBUG
377 // Copy-on-write arrays must be shallow (and simple).
378 for (int i = 0; i < content->length(); i++) {
379 ASSERT(!content->get(i)->IsFixedArray());
380 }
381#endif
382 } else {
383 for (int i = 0; i < content->length(); i++) {
384 if (content->get(i)->IsFixedArray()) {
385 // The value contains the constant_properties of a
386 // simple object literal.
387 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
388 Handle<Object> result =
389 CreateLiteralBoilerplate(literals, fa);
390 if (result.is_null()) return result;
391 content->set(i, *result);
392 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000393 }
394 }
395
396 // Set the elements.
397 Handle<JSArray>::cast(object)->SetContent(*content);
398 return object;
399}
400
401
402static Handle<Object> CreateLiteralBoilerplate(
403 Handle<FixedArray> literals,
404 Handle<FixedArray> array) {
405 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
406 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000407 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
408 return CreateObjectLiteralBoilerplate(literals, elements, true);
409 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
410 return CreateObjectLiteralBoilerplate(literals, elements, false);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000411 case CompileTimeValue::ARRAY_LITERAL:
412 return CreateArrayLiteralBoilerplate(literals, elements);
413 default:
414 UNREACHABLE();
415 return Handle<Object>::null();
416 }
417}
418
419
lrn@chromium.org303ada72010-10-27 09:33:13 +0000420static MaybeObject* Runtime_CreateArrayLiteralBoilerplate(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000421 // Takes a FixedArray of elements containing the literal elements of
422 // the array literal and produces JSArray with those elements.
423 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000424 // which contains the context from which to get the Array function
425 // to use for creating the array literal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000426 HandleScope scope;
427 ASSERT(args.length() == 3);
428 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
429 CONVERT_SMI_CHECKED(literals_index, args[1]);
430 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000431
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000432 Handle<Object> object = CreateArrayLiteralBoilerplate(literals, elements);
433 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000434
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000435 // Update the functions literal and return the boilerplate.
436 literals->set(literals_index, *object);
437 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000438}
439
440
lrn@chromium.org303ada72010-10-27 09:33:13 +0000441static MaybeObject* Runtime_CreateObjectLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000442 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000443 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000444 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
445 CONVERT_SMI_CHECKED(literals_index, args[1]);
446 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000447 CONVERT_SMI_CHECKED(fast_elements, args[3]);
448 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000449
450 // Check if boilerplate exists. If not, create it first.
451 Handle<Object> boilerplate(literals->get(literals_index));
452 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000453 boilerplate = CreateObjectLiteralBoilerplate(literals,
454 constant_properties,
455 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000456 if (boilerplate.is_null()) return Failure::Exception();
457 // Update the functions literal and return the boilerplate.
458 literals->set(literals_index, *boilerplate);
459 }
460 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
461}
462
463
lrn@chromium.org303ada72010-10-27 09:33:13 +0000464static MaybeObject* Runtime_CreateObjectLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000465 HandleScope scope;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000466 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000467 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
468 CONVERT_SMI_CHECKED(literals_index, args[1]);
469 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000470 CONVERT_SMI_CHECKED(fast_elements, args[3]);
471 bool should_have_fast_elements = fast_elements == 1;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000472
473 // Check if boilerplate exists. If not, create it first.
474 Handle<Object> boilerplate(literals->get(literals_index));
475 if (*boilerplate == Heap::undefined_value()) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000476 boilerplate = CreateObjectLiteralBoilerplate(literals,
477 constant_properties,
478 should_have_fast_elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000479 if (boilerplate.is_null()) return Failure::Exception();
480 // Update the functions literal and return the boilerplate.
481 literals->set(literals_index, *boilerplate);
482 }
483 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
484}
485
486
lrn@chromium.org303ada72010-10-27 09:33:13 +0000487static MaybeObject* Runtime_CreateArrayLiteral(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000488 HandleScope scope;
489 ASSERT(args.length() == 3);
490 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
491 CONVERT_SMI_CHECKED(literals_index, args[1]);
492 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
493
494 // Check if boilerplate exists. If not, create it first.
495 Handle<Object> boilerplate(literals->get(literals_index));
496 if (*boilerplate == Heap::undefined_value()) {
497 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
498 if (boilerplate.is_null()) return Failure::Exception();
499 // Update the functions literal and return the boilerplate.
500 literals->set(literals_index, *boilerplate);
501 }
502 return DeepCopyBoilerplate(JSObject::cast(*boilerplate));
503}
504
505
lrn@chromium.org303ada72010-10-27 09:33:13 +0000506static MaybeObject* Runtime_CreateArrayLiteralShallow(Arguments args) {
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000507 HandleScope scope;
508 ASSERT(args.length() == 3);
509 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
510 CONVERT_SMI_CHECKED(literals_index, args[1]);
511 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
512
513 // Check if boilerplate exists. If not, create it first.
514 Handle<Object> boilerplate(literals->get(literals_index));
515 if (*boilerplate == Heap::undefined_value()) {
516 boilerplate = CreateArrayLiteralBoilerplate(literals, elements);
517 if (boilerplate.is_null()) return Failure::Exception();
518 // Update the functions literal and return the boilerplate.
519 literals->set(literals_index, *boilerplate);
520 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000521 if (JSObject::cast(*boilerplate)->elements()->map() ==
522 Heap::fixed_cow_array_map()) {
523 Counters::cow_arrays_created_runtime.Increment();
524 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000525 return Heap::CopyJSObject(JSObject::cast(*boilerplate));
526}
527
528
lrn@chromium.org303ada72010-10-27 09:33:13 +0000529static MaybeObject* Runtime_CreateCatchExtensionObject(Arguments args) {
ager@chromium.org32912102009-01-16 10:38:43 +0000530 ASSERT(args.length() == 2);
531 CONVERT_CHECKED(String, key, args[0]);
532 Object* value = args[1];
533 // Create a catch context extension object.
534 JSFunction* constructor =
535 Top::context()->global_context()->context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000536 Object* object;
537 { MaybeObject* maybe_object = Heap::AllocateJSObject(constructor);
538 if (!maybe_object->ToObject(&object)) return maybe_object;
539 }
ager@chromium.org32912102009-01-16 10:38:43 +0000540 // Assign the exception value to the catch variable and make sure
541 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000542 { MaybeObject* maybe_value =
543 JSObject::cast(object)->SetProperty(key, value, DONT_DELETE);
544 if (!maybe_value->ToObject(&value)) return maybe_value;
545 }
ager@chromium.org32912102009-01-16 10:38:43 +0000546 return object;
547}
548
549
lrn@chromium.org303ada72010-10-27 09:33:13 +0000550static MaybeObject* Runtime_ClassOf(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000551 NoHandleAllocation ha;
552 ASSERT(args.length() == 1);
553 Object* obj = args[0];
554 if (!obj->IsJSObject()) return Heap::null_value();
555 return JSObject::cast(obj)->class_name();
556}
557
ager@chromium.org7c537e22008-10-16 08:43:32 +0000558
lrn@chromium.org303ada72010-10-27 09:33:13 +0000559static MaybeObject* Runtime_IsInPrototypeChain(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000560 NoHandleAllocation ha;
561 ASSERT(args.length() == 2);
562 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
563 Object* O = args[0];
564 Object* V = args[1];
565 while (true) {
566 Object* prototype = V->GetPrototype();
567 if (prototype->IsNull()) return Heap::false_value();
568 if (O == prototype) return Heap::true_value();
569 V = prototype;
570 }
571}
572
573
ager@chromium.org9085a012009-05-11 19:22:57 +0000574// Inserts an object as the hidden prototype of another object.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000575static MaybeObject* Runtime_SetHiddenPrototype(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000576 NoHandleAllocation ha;
577 ASSERT(args.length() == 2);
578 CONVERT_CHECKED(JSObject, jsobject, args[0]);
579 CONVERT_CHECKED(JSObject, proto, args[1]);
580
581 // Sanity checks. The old prototype (that we are replacing) could
582 // theoretically be null, but if it is not null then check that we
583 // didn't already install a hidden prototype here.
584 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
585 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
586 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
587
588 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000589 Object* map_or_failure;
590 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
591 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
592 return maybe_map_or_failure;
593 }
594 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000595 Map* new_proto_map = Map::cast(map_or_failure);
596
lrn@chromium.org303ada72010-10-27 09:33:13 +0000597 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
598 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
599 return maybe_map_or_failure;
600 }
601 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000602 Map* new_map = Map::cast(map_or_failure);
603
604 // Set proto's prototype to be the old prototype of the object.
605 new_proto_map->set_prototype(jsobject->GetPrototype());
606 proto->set_map(new_proto_map);
607 new_proto_map->set_is_hidden_prototype();
608
609 // Set the object's prototype to proto.
610 new_map->set_prototype(proto);
611 jsobject->set_map(new_map);
612
613 return Heap::undefined_value();
614}
615
616
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000617// Sets the magic number that identifies a function as one of the special
618// math functions that can be inlined.
619static MaybeObject* Runtime_SetMathFunctionId(Arguments args) {
620 NoHandleAllocation ha;
621 ASSERT(args.length() == 2);
622 CONVERT_CHECKED(JSFunction, function, args[0]);
623 CONVERT_CHECKED(Smi, id, args[1]);
624 RUNTIME_ASSERT(id->value() >= 0);
625 RUNTIME_ASSERT(id->value() < SharedFunctionInfo::max_math_id_number());
626
627 function->shared()->set_math_function_id(id->value());
628
629 return Heap::undefined_value();
630}
631
632
lrn@chromium.org303ada72010-10-27 09:33:13 +0000633static MaybeObject* Runtime_IsConstructCall(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000634 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000635 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000636 JavaScriptFrameIterator it;
637 return Heap::ToBoolean(it.frame()->IsConstructor());
638}
639
640
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000641// Recursively traverses hidden prototypes if property is not found
642static void GetOwnPropertyImplementation(JSObject* obj,
643 String* name,
644 LookupResult* result) {
645 obj->LocalLookupRealNamedProperty(name, result);
646
647 if (!result->IsProperty()) {
648 Object* proto = obj->GetPrototype();
649 if (proto->IsJSObject() &&
650 JSObject::cast(proto)->map()->is_hidden_prototype())
651 GetOwnPropertyImplementation(JSObject::cast(proto),
652 name, result);
653 }
654}
655
656
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000657// Enumerator used as indices into the array returned from GetOwnProperty
658enum PropertyDescriptorIndices {
659 IS_ACCESSOR_INDEX,
660 VALUE_INDEX,
661 GETTER_INDEX,
662 SETTER_INDEX,
663 WRITABLE_INDEX,
664 ENUMERABLE_INDEX,
665 CONFIGURABLE_INDEX,
666 DESCRIPTOR_SIZE
667};
668
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000669// Returns an array with the property description:
670// if args[1] is not a property on args[0]
671// returns undefined
672// if args[1] is a data property on args[0]
673// [false, value, Writeable, Enumerable, Configurable]
674// if args[1] is an accessor on args[0]
675// [true, GetFunction, SetFunction, Enumerable, Configurable]
lrn@chromium.org303ada72010-10-27 09:33:13 +0000676static MaybeObject* Runtime_GetOwnProperty(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000677 ASSERT(args.length() == 2);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000678 HandleScope scope;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000679 Handle<FixedArray> elms = Factory::NewFixedArray(DESCRIPTOR_SIZE);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000680 Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms);
681 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000682 CONVERT_ARG_CHECKED(JSObject, obj, 0);
683 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000684
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000685 // This could be an element.
686 uint32_t index;
687 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000688 switch (obj->HasLocalElement(index)) {
689 case JSObject::UNDEFINED_ELEMENT:
690 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000691
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000692 case JSObject::STRING_CHARACTER_ELEMENT: {
693 // Special handling of string objects according to ECMAScript 5
694 // 15.5.5.2. Note that this might be a string object with elements
695 // other than the actual string value. This is covered by the
696 // subsequent cases.
697 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
698 Handle<String> str(String::cast(js_value->value()));
699 Handle<String> substr = SubString(str, index, index+1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000700
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000701 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
702 elms->set(VALUE_INDEX, *substr);
703 elms->set(WRITABLE_INDEX, Heap::false_value());
704 elms->set(ENUMERABLE_INDEX, Heap::false_value());
705 elms->set(CONFIGURABLE_INDEX, Heap::false_value());
706 return *desc;
707 }
708
709 case JSObject::INTERCEPTED_ELEMENT:
710 case JSObject::FAST_ELEMENT: {
711 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
712 Handle<Object> element = GetElement(Handle<Object>(obj), index);
713 elms->set(VALUE_INDEX, *element);
714 elms->set(WRITABLE_INDEX, Heap::true_value());
715 elms->set(ENUMERABLE_INDEX, Heap::true_value());
716 elms->set(CONFIGURABLE_INDEX, Heap::true_value());
717 return *desc;
718 }
719
720 case JSObject::DICTIONARY_ELEMENT: {
721 NumberDictionary* dictionary = obj->element_dictionary();
722 int entry = dictionary->FindEntry(index);
723 ASSERT(entry != NumberDictionary::kNotFound);
724 PropertyDetails details = dictionary->DetailsAt(entry);
725 switch (details.type()) {
726 case CALLBACKS: {
727 // This is an accessor property with getter and/or setter.
728 FixedArray* callbacks =
729 FixedArray::cast(dictionary->ValueAt(entry));
730 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
731 elms->set(GETTER_INDEX, callbacks->get(0));
732 elms->set(SETTER_INDEX, callbacks->get(1));
733 break;
734 }
735 case NORMAL:
736 // This is a data property.
737 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
738 elms->set(VALUE_INDEX, dictionary->ValueAt(entry));
739 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
740 break;
741 default:
742 UNREACHABLE();
743 break;
744 }
745 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum()));
746 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete()));
747 return *desc;
748 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000749 }
750 }
751
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000752 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000753 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000754
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000755 if (!result.IsProperty()) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000756 return Heap::undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000757 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000758 if (result.type() == CALLBACKS) {
759 Object* structure = result.GetCallbackObject();
ager@chromium.org5c838252010-02-19 08:53:10 +0000760 if (structure->IsProxy() || structure->IsAccessorInfo()) {
761 // Property that is internally implemented as a callback or
762 // an API defined callback.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000763 Object* value;
764 { MaybeObject* maybe_value = obj->GetPropertyWithCallback(
765 *obj, structure, *name, result.holder());
766 if (!maybe_value->ToObject(&value)) return maybe_value;
767 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000768 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
769 elms->set(VALUE_INDEX, value);
770 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000771 } else if (structure->IsFixedArray()) {
772 // __defineGetter__/__defineSetter__ callback.
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000773 elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
774 elms->set(GETTER_INDEX, FixedArray::cast(structure)->get(0));
775 elms->set(SETTER_INDEX, FixedArray::cast(structure)->get(1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000776 } else {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000777 return Heap::undefined_value();
778 }
779 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000780 elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
781 elms->set(VALUE_INDEX, result.GetLazyValue());
782 elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000783 }
784
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000785 elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
786 elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000787 return *desc;
788}
789
790
lrn@chromium.org303ada72010-10-27 09:33:13 +0000791static MaybeObject* Runtime_PreventExtensions(Arguments args) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000792 ASSERT(args.length() == 1);
793 CONVERT_CHECKED(JSObject, obj, args[0]);
794 return obj->PreventExtensions();
795}
796
lrn@chromium.org303ada72010-10-27 09:33:13 +0000797static MaybeObject* Runtime_IsExtensible(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000798 ASSERT(args.length() == 1);
799 CONVERT_CHECKED(JSObject, obj, args[0]);
800 return obj->map()->is_extensible() ? Heap::true_value()
801 : Heap::false_value();
802}
803
804
lrn@chromium.org303ada72010-10-27 09:33:13 +0000805static MaybeObject* Runtime_RegExpCompile(Arguments args) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000806 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000807 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000808 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
809 CONVERT_ARG_CHECKED(String, pattern, 1);
810 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000811 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
812 if (result.is_null()) return Failure::Exception();
813 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000814}
815
816
lrn@chromium.org303ada72010-10-27 09:33:13 +0000817static MaybeObject* Runtime_CreateApiFunction(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000818 HandleScope scope;
819 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000820 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000821 return *Factory::CreateApiFunction(data);
822}
823
824
lrn@chromium.org303ada72010-10-27 09:33:13 +0000825static MaybeObject* Runtime_IsTemplate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000826 ASSERT(args.length() == 1);
827 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000828 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000829 return Heap::ToBoolean(result);
830}
831
832
lrn@chromium.org303ada72010-10-27 09:33:13 +0000833static MaybeObject* Runtime_GetTemplateField(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000834 ASSERT(args.length() == 2);
835 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000836 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000837 int index = field->value();
838 int offset = index * kPointerSize + HeapObject::kHeaderSize;
839 InstanceType type = templ->map()->instance_type();
840 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
841 type == OBJECT_TEMPLATE_INFO_TYPE);
842 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000843 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000844 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
845 } else {
846 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
847 }
848 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000849}
850
851
lrn@chromium.org303ada72010-10-27 09:33:13 +0000852static MaybeObject* Runtime_DisableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000853 ASSERT(args.length() == 1);
854 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000855 Map* old_map = object->map();
856 bool needs_access_checks = old_map->is_access_check_needed();
857 if (needs_access_checks) {
858 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000859 Object* new_map;
860 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
861 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
862 }
ager@chromium.org32912102009-01-16 10:38:43 +0000863
864 Map::cast(new_map)->set_is_access_check_needed(false);
865 object->set_map(Map::cast(new_map));
866 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000867 return needs_access_checks ? Heap::true_value() : Heap::false_value();
868}
869
870
lrn@chromium.org303ada72010-10-27 09:33:13 +0000871static MaybeObject* Runtime_EnableAccessChecks(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000872 ASSERT(args.length() == 1);
873 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +0000874 Map* old_map = object->map();
875 if (!old_map->is_access_check_needed()) {
876 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000877 Object* new_map;
878 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
879 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
880 }
ager@chromium.org32912102009-01-16 10:38:43 +0000881
882 Map::cast(new_map)->set_is_access_check_needed(true);
883 object->set_map(Map::cast(new_map));
884 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000885 return Heap::undefined_value();
886}
887
888
lrn@chromium.org303ada72010-10-27 09:33:13 +0000889static Failure* ThrowRedeclarationError(const char* type, Handle<String> name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000890 HandleScope scope;
891 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
892 Handle<Object> args[2] = { type_handle, name };
893 Handle<Object> error =
894 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
895 return Top::Throw(*error);
896}
897
898
lrn@chromium.org303ada72010-10-27 09:33:13 +0000899static MaybeObject* Runtime_DeclareGlobals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000900 HandleScope scope;
901 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
902
ager@chromium.org3811b432009-10-28 14:53:37 +0000903 Handle<Context> context = args.at<Context>(0);
904 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000905 bool is_eval = Smi::cast(args[2])->value() == 1;
906
907 // Compute the property attributes. According to ECMA-262, section
908 // 13, page 71, the property must be read-only and
909 // non-deletable. However, neither SpiderMonkey nor KJS creates the
910 // property as read-only, so we don't either.
911 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
912
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000913 // Traverse the name/value pairs and set the properties.
914 int length = pairs->length();
915 for (int i = 0; i < length; i += 2) {
916 HandleScope scope;
917 Handle<String> name(String::cast(pairs->get(i)));
918 Handle<Object> value(pairs->get(i + 1));
919
920 // We have to declare a global const property. To capture we only
921 // assign to it when evaluating the assignment for "const x =
922 // <expr>" the initial value is the hole.
923 bool is_const_property = value->IsTheHole();
924
925 if (value->IsUndefined() || is_const_property) {
926 // Lookup the property in the global object, and don't set the
927 // value of the variable if the property is already there.
928 LookupResult lookup;
929 global->Lookup(*name, &lookup);
930 if (lookup.IsProperty()) {
931 // Determine if the property is local by comparing the holder
932 // against the global object. The information will be used to
933 // avoid throwing re-declaration errors when declaring
934 // variables or constants that exist in the prototype chain.
935 bool is_local = (*global == lookup.holder());
936 // Get the property attributes and determine if the property is
937 // read-only.
938 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
939 bool is_read_only = (attributes & READ_ONLY) != 0;
940 if (lookup.type() == INTERCEPTOR) {
941 // If the interceptor says the property is there, we
942 // just return undefined without overwriting the property.
943 // Otherwise, we continue to setting the property.
944 if (attributes != ABSENT) {
945 // Check if the existing property conflicts with regards to const.
946 if (is_local && (is_read_only || is_const_property)) {
947 const char* type = (is_read_only) ? "const" : "var";
948 return ThrowRedeclarationError(type, name);
949 };
950 // The property already exists without conflicting: Go to
951 // the next declaration.
952 continue;
953 }
954 // Fall-through and introduce the absent property by using
955 // SetProperty.
956 } else {
957 if (is_local && (is_read_only || is_const_property)) {
958 const char* type = (is_read_only) ? "const" : "var";
959 return ThrowRedeclarationError(type, name);
960 }
961 // The property already exists without conflicting: Go to
962 // the next declaration.
963 continue;
964 }
965 }
966 } else {
967 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000968 Handle<SharedFunctionInfo> shared =
969 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000970 Handle<JSFunction> function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000971 Factory::NewFunctionFromSharedFunctionInfo(shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000972 value = function;
973 }
974
975 LookupResult lookup;
976 global->LocalLookup(*name, &lookup);
977
978 PropertyAttributes attributes = is_const_property
979 ? static_cast<PropertyAttributes>(base | READ_ONLY)
980 : base;
981
982 if (lookup.IsProperty()) {
983 // There's a local property that we need to overwrite because
984 // we're either declaring a function or there's an interceptor
985 // that claims the property is absent.
986
987 // Check for conflicting re-declarations. We cannot have
988 // conflicting types in case of intercepted properties because
989 // they are absent.
990 if (lookup.type() != INTERCEPTOR &&
991 (lookup.IsReadOnly() || is_const_property)) {
992 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
993 return ThrowRedeclarationError(type, name);
994 }
995 SetProperty(global, name, value, attributes);
996 } else {
997 // If a property with this name does not already exist on the
998 // global object add the property locally. We take special
999 // precautions to always add it as a local property even in case
1000 // of callbacks in the prototype chain (this rules out using
1001 // SetProperty). Also, we must use the handle-based version to
1002 // avoid GC issues.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001003 IgnoreAttributesAndSetLocalProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001004 }
1005 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001006
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007 return Heap::undefined_value();
1008}
1009
1010
lrn@chromium.org303ada72010-10-27 09:33:13 +00001011static MaybeObject* Runtime_DeclareContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001012 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001013 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001014
ager@chromium.org7c537e22008-10-16 08:43:32 +00001015 CONVERT_ARG_CHECKED(Context, context, 0);
1016 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001017 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001018 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001019 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001020 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001021
1022 // Declarations are always done in the function context.
1023 context = Handle<Context>(context->fcontext());
1024
1025 int index;
1026 PropertyAttributes attributes;
1027 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001028 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001029 context->Lookup(name, flags, &index, &attributes);
1030
1031 if (attributes != ABSENT) {
1032 // The name was declared before; check for conflicting
1033 // re-declarations: This is similar to the code in parser.cc in
1034 // the AstBuildingParser::Declare function.
1035 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1036 // Functions are not read-only.
1037 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1038 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
1039 return ThrowRedeclarationError(type, name);
1040 }
1041
1042 // Initialize it if necessary.
1043 if (*initial_value != NULL) {
1044 if (index >= 0) {
1045 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001046 // the function context or the arguments object.
1047 if (holder->IsContext()) {
1048 ASSERT(holder.is_identical_to(context));
1049 if (((attributes & READ_ONLY) == 0) ||
1050 context->get(index)->IsTheHole()) {
1051 context->set(index, *initial_value);
1052 }
1053 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001054 // The holder is an arguments object.
1055 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1056 SetElement(arguments, index, initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001057 }
1058 } else {
1059 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001060 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001061 SetProperty(context_ext, name, initial_value, mode);
1062 }
1063 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001064
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001065 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001066 // The property is not in the function context. It needs to be
1067 // "declared" in the function context's extension context, or in the
1068 // global context.
1069 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001070 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001071 // The function context's extension context exists - use it.
1072 context_ext = Handle<JSObject>(context->extension());
1073 } else {
1074 // The function context's extension context does not exists - allocate
1075 // it.
1076 context_ext = Factory::NewJSObject(Top::context_extension_function());
1077 // And store it in the extension slot.
1078 context->set_extension(*context_ext);
1079 }
1080 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001081
ager@chromium.org7c537e22008-10-16 08:43:32 +00001082 // Declare the property by setting it to the initial value if provided,
1083 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1084 // constant declarations).
1085 ASSERT(!context_ext->HasLocalProperty(*name));
1086 Handle<Object> value(Heap::undefined_value());
1087 if (*initial_value != NULL) value = initial_value;
1088 SetProperty(context_ext, name, value, mode);
1089 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
1090 }
1091
1092 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001093}
1094
1095
lrn@chromium.org303ada72010-10-27 09:33:13 +00001096static MaybeObject* Runtime_InitializeVarGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001097 NoHandleAllocation nha;
1098
1099 // Determine if we need to assign to the variable if it already
1100 // exists (based on the number of arguments).
1101 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
1102 bool assign = args.length() == 2;
1103
1104 CONVERT_ARG_CHECKED(String, name, 0);
1105 GlobalObject* global = Top::context()->global();
1106
1107 // According to ECMA-262, section 12.2, page 62, the property must
1108 // not be deletable.
1109 PropertyAttributes attributes = DONT_DELETE;
1110
1111 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001112 // there, there is a property with this name in the prototype chain.
1113 // We follow Safari and Firefox behavior and only set the property
1114 // locally if there is an explicit initialization value that we have
1115 // to assign to the property. When adding the property we take
1116 // special precautions to always add it as a local property even in
1117 // case of callbacks in the prototype chain (this rules out using
1118 // SetProperty). We have IgnoreAttributesAndSetLocalProperty for
1119 // this.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001120 // Note that objects can have hidden prototypes, so we need to traverse
1121 // the whole chain of hidden prototypes to do a 'local' lookup.
1122 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001123 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001124 while (true) {
1125 real_holder->LocalLookup(*name, &lookup);
1126 if (lookup.IsProperty()) {
1127 // Determine if this is a redeclaration of something read-only.
1128 if (lookup.IsReadOnly()) {
1129 // If we found readonly property on one of hidden prototypes,
1130 // just shadow it.
1131 if (real_holder != Top::context()->global()) break;
1132 return ThrowRedeclarationError("const", name);
1133 }
1134
1135 // Determine if this is a redeclaration of an intercepted read-only
1136 // property and figure out if the property exists at all.
1137 bool found = true;
1138 PropertyType type = lookup.type();
1139 if (type == INTERCEPTOR) {
1140 HandleScope handle_scope;
1141 Handle<JSObject> holder(real_holder);
1142 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1143 real_holder = *holder;
1144 if (intercepted == ABSENT) {
1145 // The interceptor claims the property isn't there. We need to
1146 // make sure to introduce it.
1147 found = false;
1148 } else if ((intercepted & READ_ONLY) != 0) {
1149 // The property is present, but read-only. Since we're trying to
1150 // overwrite it with a variable declaration we must throw a
1151 // re-declaration error. However if we found readonly property
1152 // on one of hidden prototypes, just shadow it.
1153 if (real_holder != Top::context()->global()) break;
1154 return ThrowRedeclarationError("const", name);
1155 }
1156 }
1157
1158 if (found && !assign) {
1159 // The global property is there and we're not assigning any value
1160 // to it. Just return.
1161 return Heap::undefined_value();
1162 }
1163
1164 // Assign the value (or undefined) to the property.
1165 Object* value = (assign) ? args[1] : Heap::undefined_value();
1166 return real_holder->SetProperty(&lookup, *name, value, attributes);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001167 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001168
1169 Object* proto = real_holder->GetPrototype();
1170 if (!proto->IsJSObject())
1171 break;
1172
1173 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1174 break;
1175
1176 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001177 }
1178
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001179 global = Top::context()->global();
1180 if (assign) {
1181 return global->IgnoreAttributesAndSetLocalProperty(*name,
1182 args[1],
1183 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001184 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001185 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001186}
1187
1188
lrn@chromium.org303ada72010-10-27 09:33:13 +00001189static MaybeObject* Runtime_InitializeConstGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001190 // All constants are declared with an initial value. The name
1191 // of the constant is the first argument and the initial value
1192 // is the second.
1193 RUNTIME_ASSERT(args.length() == 2);
1194 CONVERT_ARG_CHECKED(String, name, 0);
1195 Handle<Object> value = args.at<Object>(1);
1196
1197 // Get the current global object from top.
1198 GlobalObject* global = Top::context()->global();
1199
1200 // According to ECMA-262, section 12.2, page 62, the property must
1201 // not be deletable. Since it's a const, it must be READ_ONLY too.
1202 PropertyAttributes attributes =
1203 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1204
1205 // Lookup the property locally in the global object. If it isn't
1206 // there, we add the property and take special precautions to always
1207 // add it as a local property even in case of callbacks in the
1208 // prototype chain (this rules out using SetProperty).
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001209 // We use IgnoreAttributesAndSetLocalProperty instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001210 LookupResult lookup;
1211 global->LocalLookup(*name, &lookup);
1212 if (!lookup.IsProperty()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001213 return global->IgnoreAttributesAndSetLocalProperty(*name,
1214 *value,
1215 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001216 }
1217
1218 // Determine if this is a redeclaration of something not
1219 // read-only. In case the result is hidden behind an interceptor we
1220 // need to ask it for the property attributes.
1221 if (!lookup.IsReadOnly()) {
1222 if (lookup.type() != INTERCEPTOR) {
1223 return ThrowRedeclarationError("var", name);
1224 }
1225
1226 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1227
1228 // Throw re-declaration error if the intercepted property is present
1229 // but not read-only.
1230 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1231 return ThrowRedeclarationError("var", name);
1232 }
1233
1234 // Restore global object from context (in case of GC) and continue
1235 // with setting the value because the property is either absent or
1236 // read-only. We also have to do redo the lookup.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001237 HandleScope handle_scope;
1238 Handle<GlobalObject>global(Top::context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001239
1240 // BUG 1213579: Handle the case where we have to set a read-only
1241 // property through an interceptor and only do it if it's
1242 // uninitialized, e.g. the hole. Nirk...
lrn@chromium.org303ada72010-10-27 09:33:13 +00001243 SetProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001244 return *value;
1245 }
1246
1247 // Set the value, but only we're assigning the initial value to a
1248 // constant. For now, we determine this by checking if the
1249 // current value is the hole.
1250 PropertyType type = lookup.type();
1251 if (type == FIELD) {
1252 FixedArray* properties = global->properties();
1253 int index = lookup.GetFieldIndex();
1254 if (properties->get(index)->IsTheHole()) {
1255 properties->set(index, *value);
1256 }
1257 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001258 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1259 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001260 }
1261 } else {
1262 // Ignore re-initialization of constants that have already been
1263 // assigned a function value.
1264 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1265 }
1266
1267 // Use the set value as the result of the operation.
1268 return *value;
1269}
1270
1271
lrn@chromium.org303ada72010-10-27 09:33:13 +00001272static MaybeObject* Runtime_InitializeConstContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001273 HandleScope scope;
1274 ASSERT(args.length() == 3);
1275
1276 Handle<Object> value(args[0]);
1277 ASSERT(!value->IsTheHole());
1278 CONVERT_ARG_CHECKED(Context, context, 1);
1279 Handle<String> name(String::cast(args[2]));
1280
1281 // Initializations are always done in the function context.
1282 context = Handle<Context>(context->fcontext());
1283
1284 int index;
1285 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001286 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001287 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001288 context->Lookup(name, flags, &index, &attributes);
1289
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001290 // In most situations, the property introduced by the const
1291 // declaration should be present in the context extension object.
1292 // However, because declaration and initialization are separate, the
1293 // property might have been deleted (if it was introduced by eval)
1294 // before we reach the initialization point.
1295 //
1296 // Example:
1297 //
1298 // function f() { eval("delete x; const x;"); }
1299 //
1300 // In that case, the initialization behaves like a normal assignment
1301 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001302 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001303 // Property was found in a context.
1304 if (holder->IsContext()) {
1305 // The holder cannot be the function context. If it is, there
1306 // should have been a const redeclaration error when declaring
1307 // the const property.
1308 ASSERT(!holder.is_identical_to(context));
1309 if ((attributes & READ_ONLY) == 0) {
1310 Handle<Context>::cast(holder)->set(index, *value);
1311 }
1312 } else {
1313 // The holder is an arguments object.
1314 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001315 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
1316 SetElement(arguments, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001317 }
1318 return *value;
1319 }
1320
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001321 // The property could not be found, we introduce it in the global
1322 // context.
1323 if (attributes == ABSENT) {
1324 Handle<JSObject> global = Handle<JSObject>(Top::context()->global());
1325 SetProperty(global, name, value, NONE);
1326 return *value;
1327 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001328
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001329 // The property was present in a context extension object.
1330 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001332 if (*context_ext == context->extension()) {
1333 // This is the property that was introduced by the const
1334 // declaration. Set it if it hasn't been set before. NOTE: We
1335 // cannot use GetProperty() to get the current value as it
1336 // 'unholes' the value.
1337 LookupResult lookup;
1338 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1339 ASSERT(lookup.IsProperty()); // the property was declared
1340 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1341
1342 PropertyType type = lookup.type();
1343 if (type == FIELD) {
1344 FixedArray* properties = context_ext->properties();
1345 int index = lookup.GetFieldIndex();
1346 if (properties->get(index)->IsTheHole()) {
1347 properties->set(index, *value);
1348 }
1349 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001350 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1351 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001352 }
1353 } else {
1354 // We should not reach here. Any real, named property should be
1355 // either a field or a dictionary slot.
1356 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001357 }
1358 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001359 // The property was found in a different context extension object.
1360 // Set it if it is not a read-only property.
1361 if ((attributes & READ_ONLY) == 0) {
1362 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
1363 // Setting a property might throw an exception. Exceptions
1364 // are converted to empty handles in handle operations. We
1365 // need to convert back to exceptions here.
1366 if (set.is_null()) {
1367 ASSERT(Top::has_pending_exception());
1368 return Failure::Exception();
1369 }
1370 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001371 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001372
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001373 return *value;
1374}
1375
1376
lrn@chromium.org303ada72010-10-27 09:33:13 +00001377static MaybeObject* Runtime_OptimizeObjectForAddingMultipleProperties(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001378 Arguments args) {
1379 HandleScope scope;
1380 ASSERT(args.length() == 2);
1381 CONVERT_ARG_CHECKED(JSObject, object, 0);
1382 CONVERT_SMI_CHECKED(properties, args[1]);
1383 if (object->HasFastProperties()) {
1384 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1385 }
1386 return *object;
1387}
1388
1389
lrn@chromium.org303ada72010-10-27 09:33:13 +00001390static MaybeObject* Runtime_RegExpExec(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001391 HandleScope scope;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001392 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001393 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1394 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001395 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001396 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001397 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001398 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001399 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001400 RUNTIME_ASSERT(index >= 0);
1401 RUNTIME_ASSERT(index <= subject->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001402 Counters::regexp_entry_runtime.Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001403 Handle<Object> result = RegExpImpl::Exec(regexp,
1404 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001405 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001406 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001407 if (result.is_null()) return Failure::Exception();
1408 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001409}
1410
1411
lrn@chromium.org303ada72010-10-27 09:33:13 +00001412static MaybeObject* Runtime_RegExpConstructResult(Arguments args) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001413 ASSERT(args.length() == 3);
1414 CONVERT_SMI_CHECKED(elements_count, args[0]);
1415 if (elements_count > JSArray::kMaxFastElementsLength) {
1416 return Top::ThrowIllegalOperation();
1417 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001418 Object* new_object;
1419 { MaybeObject* maybe_new_object =
1420 Heap::AllocateFixedArrayWithHoles(elements_count);
1421 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1422 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001423 FixedArray* elements = FixedArray::cast(new_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001424 { MaybeObject* maybe_new_object = Heap::AllocateRaw(JSRegExpResult::kSize,
1425 NEW_SPACE,
1426 OLD_POINTER_SPACE);
1427 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1428 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001429 {
1430 AssertNoAllocation no_gc;
1431 HandleScope scope;
1432 reinterpret_cast<HeapObject*>(new_object)->
1433 set_map(Top::global_context()->regexp_result_map());
1434 }
1435 JSArray* array = JSArray::cast(new_object);
1436 array->set_properties(Heap::empty_fixed_array());
1437 array->set_elements(elements);
1438 array->set_length(Smi::FromInt(elements_count));
1439 // Write in-object properties after the length of the array.
1440 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1441 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1442 return array;
1443}
1444
1445
lrn@chromium.org303ada72010-10-27 09:33:13 +00001446static MaybeObject* Runtime_RegExpInitializeObject(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001447 AssertNoAllocation no_alloc;
1448 ASSERT(args.length() == 5);
1449 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1450 CONVERT_CHECKED(String, source, args[1]);
1451
1452 Object* global = args[2];
1453 if (!global->IsTrue()) global = Heap::false_value();
1454
1455 Object* ignoreCase = args[3];
1456 if (!ignoreCase->IsTrue()) ignoreCase = Heap::false_value();
1457
1458 Object* multiline = args[4];
1459 if (!multiline->IsTrue()) multiline = Heap::false_value();
1460
1461 Map* map = regexp->map();
1462 Object* constructor = map->constructor();
1463 if (constructor->IsJSFunction() &&
1464 JSFunction::cast(constructor)->initial_map() == map) {
1465 // If we still have the original map, set in-object properties directly.
1466 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1467 // TODO(lrn): Consider skipping write barrier on booleans as well.
1468 // Both true and false should be in oldspace at all times.
1469 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1470 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1471 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1472 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1473 Smi::FromInt(0),
1474 SKIP_WRITE_BARRIER);
1475 return regexp;
1476 }
1477
lrn@chromium.org303ada72010-10-27 09:33:13 +00001478 // Map has changed, so use generic, but slower, method. Since these
1479 // properties were all added as DONT_DELETE they must be present and
1480 // normal so no failures can be expected.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001481 PropertyAttributes final =
1482 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1483 PropertyAttributes writable =
1484 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001485 MaybeObject* result;
1486 result = regexp->IgnoreAttributesAndSetLocalProperty(Heap::source_symbol(),
1487 source,
1488 final);
1489 ASSERT(!result->IsFailure());
1490 result = regexp->IgnoreAttributesAndSetLocalProperty(Heap::global_symbol(),
1491 global,
1492 final);
1493 ASSERT(!result->IsFailure());
1494 result =
1495 regexp->IgnoreAttributesAndSetLocalProperty(Heap::ignore_case_symbol(),
1496 ignoreCase,
1497 final);
1498 ASSERT(!result->IsFailure());
1499 result = regexp->IgnoreAttributesAndSetLocalProperty(Heap::multiline_symbol(),
1500 multiline,
1501 final);
1502 ASSERT(!result->IsFailure());
1503 result =
1504 regexp->IgnoreAttributesAndSetLocalProperty(Heap::last_index_symbol(),
1505 Smi::FromInt(0),
1506 writable);
1507 ASSERT(!result->IsFailure());
1508 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001509 return regexp;
1510}
1511
1512
lrn@chromium.org303ada72010-10-27 09:33:13 +00001513static MaybeObject* Runtime_FinishArrayPrototypeSetup(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001514 HandleScope scope;
1515 ASSERT(args.length() == 1);
1516 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1517 // This is necessary to enable fast checks for absence of elements
1518 // on Array.prototype and below.
1519 prototype->set_elements(Heap::empty_fixed_array());
1520 return Smi::FromInt(0);
1521}
1522
1523
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001524static Handle<JSFunction> InstallBuiltin(Handle<JSObject> holder,
1525 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001526 Builtins::Name builtin_name) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001527 Handle<String> key = Factory::LookupAsciiSymbol(name);
1528 Handle<Code> code(Builtins::builtin(builtin_name));
1529 Handle<JSFunction> optimized = Factory::NewFunction(key,
1530 JS_OBJECT_TYPE,
1531 JSObject::kHeaderSize,
1532 code,
1533 false);
1534 optimized->shared()->DontAdaptArguments();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001535 SetProperty(holder, key, optimized, NONE);
1536 return optimized;
1537}
1538
1539
lrn@chromium.org303ada72010-10-27 09:33:13 +00001540static MaybeObject* Runtime_SpecialArrayFunctions(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001541 HandleScope scope;
1542 ASSERT(args.length() == 1);
1543 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1544
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001545 InstallBuiltin(holder, "pop", Builtins::ArrayPop);
1546 InstallBuiltin(holder, "push", Builtins::ArrayPush);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001547 InstallBuiltin(holder, "shift", Builtins::ArrayShift);
1548 InstallBuiltin(holder, "unshift", Builtins::ArrayUnshift);
1549 InstallBuiltin(holder, "slice", Builtins::ArraySlice);
1550 InstallBuiltin(holder, "splice", Builtins::ArraySplice);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001551 InstallBuiltin(holder, "concat", Builtins::ArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001552
1553 return *holder;
1554}
1555
1556
lrn@chromium.org303ada72010-10-27 09:33:13 +00001557static MaybeObject* Runtime_GetGlobalReceiver(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001558 // Returns a real global receiver, not one of builtins object.
1559 Context* global_context = Top::context()->global()->global_context();
1560 return global_context->global()->global_receiver();
1561}
1562
1563
lrn@chromium.org303ada72010-10-27 09:33:13 +00001564static MaybeObject* Runtime_MaterializeRegExpLiteral(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001565 HandleScope scope;
1566 ASSERT(args.length() == 4);
1567 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1568 int index = Smi::cast(args[1])->value();
1569 Handle<String> pattern = args.at<String>(2);
1570 Handle<String> flags = args.at<String>(3);
1571
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001572 // Get the RegExp function from the context in the literals array.
1573 // This is the RegExp function from the context in which the
1574 // function was created. We do not use the RegExp function from the
1575 // current global context because this might be the RegExp function
1576 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001577 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001578 Handle<JSFunction>(
1579 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001580 // Compute the regular expression literal.
1581 bool has_pending_exception;
1582 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001583 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1584 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001585 if (has_pending_exception) {
1586 ASSERT(Top::has_pending_exception());
1587 return Failure::Exception();
1588 }
1589 literals->set(index, *regexp);
1590 return *regexp;
1591}
1592
1593
lrn@chromium.org303ada72010-10-27 09:33:13 +00001594static MaybeObject* Runtime_FunctionGetName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001595 NoHandleAllocation ha;
1596 ASSERT(args.length() == 1);
1597
1598 CONVERT_CHECKED(JSFunction, f, args[0]);
1599 return f->shared()->name();
1600}
1601
1602
lrn@chromium.org303ada72010-10-27 09:33:13 +00001603static MaybeObject* Runtime_FunctionSetName(Arguments args) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001604 NoHandleAllocation ha;
1605 ASSERT(args.length() == 2);
1606
1607 CONVERT_CHECKED(JSFunction, f, args[0]);
1608 CONVERT_CHECKED(String, name, args[1]);
1609 f->shared()->set_name(name);
1610 return Heap::undefined_value();
1611}
1612
1613
lrn@chromium.org303ada72010-10-27 09:33:13 +00001614static MaybeObject* Runtime_FunctionRemovePrototype(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001615 NoHandleAllocation ha;
1616 ASSERT(args.length() == 1);
1617
1618 CONVERT_CHECKED(JSFunction, f, args[0]);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001619 Object* obj;
1620 { MaybeObject* maybe_obj = f->RemovePrototype();
1621 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1622 }
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001623
1624 return Heap::undefined_value();
1625}
1626
1627
lrn@chromium.org303ada72010-10-27 09:33:13 +00001628static MaybeObject* Runtime_FunctionGetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001629 HandleScope scope;
1630 ASSERT(args.length() == 1);
1631
1632 CONVERT_CHECKED(JSFunction, fun, args[0]);
1633 Handle<Object> script = Handle<Object>(fun->shared()->script());
1634 if (!script->IsScript()) return Heap::undefined_value();
1635
1636 return *GetScriptWrapper(Handle<Script>::cast(script));
1637}
1638
1639
lrn@chromium.org303ada72010-10-27 09:33:13 +00001640static MaybeObject* Runtime_FunctionGetSourceCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001641 NoHandleAllocation ha;
1642 ASSERT(args.length() == 1);
1643
1644 CONVERT_CHECKED(JSFunction, f, args[0]);
1645 return f->shared()->GetSourceCode();
1646}
1647
1648
lrn@chromium.org303ada72010-10-27 09:33:13 +00001649static MaybeObject* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001650 NoHandleAllocation ha;
1651 ASSERT(args.length() == 1);
1652
1653 CONVERT_CHECKED(JSFunction, fun, args[0]);
1654 int pos = fun->shared()->start_position();
1655 return Smi::FromInt(pos);
1656}
1657
1658
lrn@chromium.org303ada72010-10-27 09:33:13 +00001659static MaybeObject* Runtime_FunctionGetPositionForOffset(Arguments args) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001660 ASSERT(args.length() == 2);
1661
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001662 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001663 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1664
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001665 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1666
1667 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001668 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001669}
1670
1671
1672
lrn@chromium.org303ada72010-10-27 09:33:13 +00001673static MaybeObject* Runtime_FunctionSetInstanceClassName(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001674 NoHandleAllocation ha;
1675 ASSERT(args.length() == 2);
1676
1677 CONVERT_CHECKED(JSFunction, fun, args[0]);
1678 CONVERT_CHECKED(String, name, args[1]);
1679 fun->SetInstanceClassName(name);
1680 return Heap::undefined_value();
1681}
1682
1683
lrn@chromium.org303ada72010-10-27 09:33:13 +00001684static MaybeObject* Runtime_FunctionSetLength(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001685 NoHandleAllocation ha;
1686 ASSERT(args.length() == 2);
1687
1688 CONVERT_CHECKED(JSFunction, fun, args[0]);
1689 CONVERT_CHECKED(Smi, length, args[1]);
1690 fun->shared()->set_length(length->value());
1691 return length;
1692}
1693
1694
lrn@chromium.org303ada72010-10-27 09:33:13 +00001695static MaybeObject* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001696 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001697 ASSERT(args.length() == 2);
1698
1699 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001700 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001701 Object* obj;
1702 { MaybeObject* maybe_obj =
1703 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1704 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1705 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001706 return args[0]; // return TOS
1707}
1708
1709
lrn@chromium.org303ada72010-10-27 09:33:13 +00001710static MaybeObject* Runtime_FunctionIsAPIFunction(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001711 NoHandleAllocation ha;
1712 ASSERT(args.length() == 1);
1713
1714 CONVERT_CHECKED(JSFunction, f, args[0]);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001715 return f->shared()->IsApiFunction() ? Heap::true_value()
1716 : Heap::false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001717}
1718
lrn@chromium.org303ada72010-10-27 09:33:13 +00001719static MaybeObject* Runtime_FunctionIsBuiltin(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001720 NoHandleAllocation ha;
1721 ASSERT(args.length() == 1);
1722
1723 CONVERT_CHECKED(JSFunction, f, args[0]);
1724 return f->IsBuiltin() ? Heap::true_value() : Heap::false_value();
1725}
1726
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001727
lrn@chromium.org303ada72010-10-27 09:33:13 +00001728static MaybeObject* Runtime_SetCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001729 HandleScope scope;
1730 ASSERT(args.length() == 2);
1731
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001732 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001733 Handle<Object> code = args.at<Object>(1);
1734
1735 Handle<Context> context(target->context());
1736
1737 if (!code->IsNull()) {
1738 RUNTIME_ASSERT(code->IsJSFunction());
1739 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001740 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001741
1742 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001743 return Failure::Exception();
1744 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001745 // Since we don't store the source for this we should never
1746 // optimize this.
1747 shared->code()->set_optimizable(false);
1748
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001749 // Set the code, scope info, formal parameter count,
1750 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001751 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001752 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001753 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001754 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001755 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001756 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001757 // Set the source code of the target function to undefined.
1758 // SetCode is only used for built-in constructors like String,
1759 // Array, and Object, and some web code
1760 // doesn't like seeing source code for constructors.
1761 target->shared()->set_script(Heap::undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001762 // Clear the optimization hints related to the compiled code as these are no
1763 // longer valid when the code is overwritten.
1764 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001765 context = Handle<Context>(fun->context());
1766
1767 // Make sure we get a fresh copy of the literal vector to avoid
1768 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001769 int number_of_literals = fun->NumberOfLiterals();
1770 Handle<FixedArray> literals =
1771 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001772 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001773 // Insert the object, regexp and array functions in the literals
1774 // array prefix. These are the functions that will be used when
1775 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00001776 literals->set(JSFunction::kLiteralGlobalContextIndex,
1777 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001778 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001779 // It's okay to skip the write barrier here because the literals
1780 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001781 target->set_literals(*literals, SKIP_WRITE_BARRIER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001782 target->set_next_function_link(Heap::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001783 }
1784
1785 target->set_context(*context);
1786 return *target;
1787}
1788
1789
lrn@chromium.org303ada72010-10-27 09:33:13 +00001790static MaybeObject* Runtime_SetExpectedNumberOfProperties(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001791 HandleScope scope;
1792 ASSERT(args.length() == 2);
1793 CONVERT_ARG_CHECKED(JSFunction, function, 0);
1794 CONVERT_SMI_CHECKED(num, args[1]);
1795 RUNTIME_ASSERT(num >= 0);
1796 SetExpectedNofProperties(function, num);
1797 return Heap::undefined_value();
1798}
1799
1800
lrn@chromium.org303ada72010-10-27 09:33:13 +00001801MUST_USE_RESULT static MaybeObject* CharFromCode(Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001802 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001803 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001804 if (code <= 0xffff) {
1805 return Heap::LookupSingleCharacterStringFromCode(code);
1806 }
1807 }
1808 return Heap::empty_string();
1809}
1810
1811
lrn@chromium.org303ada72010-10-27 09:33:13 +00001812static MaybeObject* Runtime_StringCharCodeAt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001813 NoHandleAllocation ha;
1814 ASSERT(args.length() == 2);
1815
1816 CONVERT_CHECKED(String, subject, args[0]);
1817 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001818 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001819
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001820 uint32_t i = 0;
1821 if (index->IsSmi()) {
1822 int value = Smi::cast(index)->value();
1823 if (value < 0) return Heap::nan_value();
1824 i = value;
1825 } else {
1826 ASSERT(index->IsHeapNumber());
1827 double value = HeapNumber::cast(index)->value();
1828 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00001829 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001830
1831 // Flatten the string. If someone wants to get a char at an index
1832 // in a cons string, it is likely that more indices will be
1833 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001834 Object* flat;
1835 { MaybeObject* maybe_flat = subject->TryFlatten();
1836 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
1837 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001838 subject = String::cast(flat);
1839
1840 if (i >= static_cast<uint32_t>(subject->length())) {
1841 return Heap::nan_value();
1842 }
1843
1844 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001845}
1846
1847
lrn@chromium.org303ada72010-10-27 09:33:13 +00001848static MaybeObject* Runtime_CharFromCode(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001849 NoHandleAllocation ha;
1850 ASSERT(args.length() == 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001851 return CharFromCode(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001852}
1853
lrn@chromium.org25156de2010-04-06 13:10:27 +00001854
1855class FixedArrayBuilder {
1856 public:
1857 explicit FixedArrayBuilder(int initial_capacity)
1858 : array_(Factory::NewFixedArrayWithHoles(initial_capacity)),
1859 length_(0) {
1860 // Require a non-zero initial size. Ensures that doubling the size to
1861 // extend the array will work.
1862 ASSERT(initial_capacity > 0);
1863 }
1864
1865 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
1866 : array_(backing_store),
1867 length_(0) {
1868 // Require a non-zero initial size. Ensures that doubling the size to
1869 // extend the array will work.
1870 ASSERT(backing_store->length() > 0);
1871 }
1872
1873 bool HasCapacity(int elements) {
1874 int length = array_->length();
1875 int required_length = length_ + elements;
1876 return (length >= required_length);
1877 }
1878
1879 void EnsureCapacity(int elements) {
1880 int length = array_->length();
1881 int required_length = length_ + elements;
1882 if (length < required_length) {
1883 int new_length = length;
1884 do {
1885 new_length *= 2;
1886 } while (new_length < required_length);
1887 Handle<FixedArray> extended_array =
1888 Factory::NewFixedArrayWithHoles(new_length);
1889 array_->CopyTo(0, *extended_array, 0, length_);
1890 array_ = extended_array;
1891 }
1892 }
1893
1894 void Add(Object* value) {
1895 ASSERT(length_ < capacity());
1896 array_->set(length_, value);
1897 length_++;
1898 }
1899
1900 void Add(Smi* value) {
1901 ASSERT(length_ < capacity());
1902 array_->set(length_, value);
1903 length_++;
1904 }
1905
1906 Handle<FixedArray> array() {
1907 return array_;
1908 }
1909
1910 int length() {
1911 return length_;
1912 }
1913
1914 int capacity() {
1915 return array_->length();
1916 }
1917
1918 Handle<JSArray> ToJSArray() {
1919 Handle<JSArray> result_array = Factory::NewJSArrayWithElements(array_);
1920 result_array->set_length(Smi::FromInt(length_));
1921 return result_array;
1922 }
1923
1924 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
1925 target_array->set_elements(*array_);
1926 target_array->set_length(Smi::FromInt(length_));
1927 return target_array;
1928 }
1929
1930 private:
1931 Handle<FixedArray> array_;
1932 int length_;
1933};
1934
1935
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001936// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001937const int kStringBuilderConcatHelperLengthBits = 11;
1938const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001939
1940template <typename schar>
1941static inline void StringBuilderConcatHelper(String*,
1942 schar*,
1943 FixedArray*,
1944 int);
1945
lrn@chromium.org25156de2010-04-06 13:10:27 +00001946typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
1947 StringBuilderSubstringLength;
1948typedef BitField<int,
1949 kStringBuilderConcatHelperLengthBits,
1950 kStringBuilderConcatHelperPositionBits>
1951 StringBuilderSubstringPosition;
1952
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001953
1954class ReplacementStringBuilder {
1955 public:
1956 ReplacementStringBuilder(Handle<String> subject, int estimated_part_count)
lrn@chromium.org25156de2010-04-06 13:10:27 +00001957 : array_builder_(estimated_part_count),
1958 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001959 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00001960 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001961 // Require a non-zero initial size. Ensures that doubling the size to
1962 // extend the array will work.
1963 ASSERT(estimated_part_count > 0);
1964 }
1965
lrn@chromium.org25156de2010-04-06 13:10:27 +00001966 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
1967 int from,
1968 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001969 ASSERT(from >= 0);
1970 int length = to - from;
1971 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001972 if (StringBuilderSubstringLength::is_valid(length) &&
1973 StringBuilderSubstringPosition::is_valid(from)) {
1974 int encoded_slice = StringBuilderSubstringLength::encode(length) |
1975 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001976 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001977 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001978 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001979 builder->Add(Smi::FromInt(-length));
1980 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001981 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00001982 }
1983
1984
1985 void EnsureCapacity(int elements) {
1986 array_builder_.EnsureCapacity(elements);
1987 }
1988
1989
1990 void AddSubjectSlice(int from, int to) {
1991 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001992 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001993 }
1994
1995
1996 void AddString(Handle<String> string) {
1997 int length = string->length();
1998 ASSERT(length > 0);
1999 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002000 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002001 is_ascii_ = false;
2002 }
2003 IncrementCharacterCount(length);
2004 }
2005
2006
2007 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002008 if (array_builder_.length() == 0) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002009 return Factory::empty_string();
2010 }
2011
2012 Handle<String> joined_string;
2013 if (is_ascii_) {
2014 joined_string = NewRawAsciiString(character_count_);
2015 AssertNoAllocation no_alloc;
2016 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2017 char* char_buffer = seq->GetChars();
2018 StringBuilderConcatHelper(*subject_,
2019 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002020 *array_builder_.array(),
2021 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002022 } else {
2023 // Non-ASCII.
2024 joined_string = NewRawTwoByteString(character_count_);
2025 AssertNoAllocation no_alloc;
2026 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2027 uc16* char_buffer = seq->GetChars();
2028 StringBuilderConcatHelper(*subject_,
2029 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002030 *array_builder_.array(),
2031 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002032 }
2033 return joined_string;
2034 }
2035
2036
2037 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002038 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002039 V8::FatalProcessOutOfMemory("String.replace result too large.");
2040 }
2041 character_count_ += by;
2042 }
2043
lrn@chromium.org25156de2010-04-06 13:10:27 +00002044 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002045 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002046 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002047
lrn@chromium.org25156de2010-04-06 13:10:27 +00002048 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002049 Handle<String> NewRawAsciiString(int size) {
2050 CALL_HEAP_FUNCTION(Heap::AllocateRawAsciiString(size), String);
2051 }
2052
2053
2054 Handle<String> NewRawTwoByteString(int size) {
2055 CALL_HEAP_FUNCTION(Heap::AllocateRawTwoByteString(size), String);
2056 }
2057
2058
2059 void AddElement(Object* element) {
2060 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002061 ASSERT(array_builder_.capacity() > array_builder_.length());
2062 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002063 }
2064
lrn@chromium.org25156de2010-04-06 13:10:27 +00002065 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002066 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002067 int character_count_;
2068 bool is_ascii_;
2069};
2070
2071
2072class CompiledReplacement {
2073 public:
2074 CompiledReplacement()
2075 : parts_(1), replacement_substrings_(0) {}
2076
2077 void Compile(Handle<String> replacement,
2078 int capture_count,
2079 int subject_length);
2080
2081 void Apply(ReplacementStringBuilder* builder,
2082 int match_from,
2083 int match_to,
2084 Handle<JSArray> last_match_info);
2085
2086 // Number of distinct parts of the replacement pattern.
2087 int parts() {
2088 return parts_.length();
2089 }
2090 private:
2091 enum PartType {
2092 SUBJECT_PREFIX = 1,
2093 SUBJECT_SUFFIX,
2094 SUBJECT_CAPTURE,
2095 REPLACEMENT_SUBSTRING,
2096 REPLACEMENT_STRING,
2097
2098 NUMBER_OF_PART_TYPES
2099 };
2100
2101 struct ReplacementPart {
2102 static inline ReplacementPart SubjectMatch() {
2103 return ReplacementPart(SUBJECT_CAPTURE, 0);
2104 }
2105 static inline ReplacementPart SubjectCapture(int capture_index) {
2106 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2107 }
2108 static inline ReplacementPart SubjectPrefix() {
2109 return ReplacementPart(SUBJECT_PREFIX, 0);
2110 }
2111 static inline ReplacementPart SubjectSuffix(int subject_length) {
2112 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2113 }
2114 static inline ReplacementPart ReplacementString() {
2115 return ReplacementPart(REPLACEMENT_STRING, 0);
2116 }
2117 static inline ReplacementPart ReplacementSubString(int from, int to) {
2118 ASSERT(from >= 0);
2119 ASSERT(to > from);
2120 return ReplacementPart(-from, to);
2121 }
2122
2123 // If tag <= 0 then it is the negation of a start index of a substring of
2124 // the replacement pattern, otherwise it's a value from PartType.
2125 ReplacementPart(int tag, int data)
2126 : tag(tag), data(data) {
2127 // Must be non-positive or a PartType value.
2128 ASSERT(tag < NUMBER_OF_PART_TYPES);
2129 }
2130 // Either a value of PartType or a non-positive number that is
2131 // the negation of an index into the replacement string.
2132 int tag;
2133 // The data value's interpretation depends on the value of tag:
2134 // tag == SUBJECT_PREFIX ||
2135 // tag == SUBJECT_SUFFIX: data is unused.
2136 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2137 // tag == REPLACEMENT_SUBSTRING ||
2138 // tag == REPLACEMENT_STRING: data is index into array of substrings
2139 // of the replacement string.
2140 // tag <= 0: Temporary representation of the substring of the replacement
2141 // string ranging over -tag .. data.
2142 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2143 // substring objects.
2144 int data;
2145 };
2146
2147 template<typename Char>
2148 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2149 Vector<Char> characters,
2150 int capture_count,
2151 int subject_length) {
2152 int length = characters.length();
2153 int last = 0;
2154 for (int i = 0; i < length; i++) {
2155 Char c = characters[i];
2156 if (c == '$') {
2157 int next_index = i + 1;
2158 if (next_index == length) { // No next character!
2159 break;
2160 }
2161 Char c2 = characters[next_index];
2162 switch (c2) {
2163 case '$':
2164 if (i > last) {
2165 // There is a substring before. Include the first "$".
2166 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2167 last = next_index + 1; // Continue after the second "$".
2168 } else {
2169 // Let the next substring start with the second "$".
2170 last = next_index;
2171 }
2172 i = next_index;
2173 break;
2174 case '`':
2175 if (i > last) {
2176 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2177 }
2178 parts->Add(ReplacementPart::SubjectPrefix());
2179 i = next_index;
2180 last = i + 1;
2181 break;
2182 case '\'':
2183 if (i > last) {
2184 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2185 }
2186 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2187 i = next_index;
2188 last = i + 1;
2189 break;
2190 case '&':
2191 if (i > last) {
2192 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2193 }
2194 parts->Add(ReplacementPart::SubjectMatch());
2195 i = next_index;
2196 last = i + 1;
2197 break;
2198 case '0':
2199 case '1':
2200 case '2':
2201 case '3':
2202 case '4':
2203 case '5':
2204 case '6':
2205 case '7':
2206 case '8':
2207 case '9': {
2208 int capture_ref = c2 - '0';
2209 if (capture_ref > capture_count) {
2210 i = next_index;
2211 continue;
2212 }
2213 int second_digit_index = next_index + 1;
2214 if (second_digit_index < length) {
2215 // Peek ahead to see if we have two digits.
2216 Char c3 = characters[second_digit_index];
2217 if ('0' <= c3 && c3 <= '9') { // Double digits.
2218 int double_digit_ref = capture_ref * 10 + c3 - '0';
2219 if (double_digit_ref <= capture_count) {
2220 next_index = second_digit_index;
2221 capture_ref = double_digit_ref;
2222 }
2223 }
2224 }
2225 if (capture_ref > 0) {
2226 if (i > last) {
2227 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2228 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002229 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002230 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2231 last = next_index + 1;
2232 }
2233 i = next_index;
2234 break;
2235 }
2236 default:
2237 i = next_index;
2238 break;
2239 }
2240 }
2241 }
2242 if (length > last) {
2243 if (last == 0) {
2244 parts->Add(ReplacementPart::ReplacementString());
2245 } else {
2246 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2247 }
2248 }
2249 }
2250
2251 ZoneList<ReplacementPart> parts_;
2252 ZoneList<Handle<String> > replacement_substrings_;
2253};
2254
2255
2256void CompiledReplacement::Compile(Handle<String> replacement,
2257 int capture_count,
2258 int subject_length) {
2259 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002260 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002261 AssertNoAllocation no_alloc;
2262 ParseReplacementPattern(&parts_,
2263 replacement->ToAsciiVector(),
2264 capture_count,
2265 subject_length);
2266 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002267 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002268 AssertNoAllocation no_alloc;
2269
2270 ParseReplacementPattern(&parts_,
2271 replacement->ToUC16Vector(),
2272 capture_count,
2273 subject_length);
2274 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002275 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002276 int substring_index = 0;
2277 for (int i = 0, n = parts_.length(); i < n; i++) {
2278 int tag = parts_[i].tag;
2279 if (tag <= 0) { // A replacement string slice.
2280 int from = -tag;
2281 int to = parts_[i].data;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002282 replacement_substrings_.Add(Factory::NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002283 parts_[i].tag = REPLACEMENT_SUBSTRING;
2284 parts_[i].data = substring_index;
2285 substring_index++;
2286 } else if (tag == REPLACEMENT_STRING) {
2287 replacement_substrings_.Add(replacement);
2288 parts_[i].data = substring_index;
2289 substring_index++;
2290 }
2291 }
2292}
2293
2294
2295void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2296 int match_from,
2297 int match_to,
2298 Handle<JSArray> last_match_info) {
2299 for (int i = 0, n = parts_.length(); i < n; i++) {
2300 ReplacementPart part = parts_[i];
2301 switch (part.tag) {
2302 case SUBJECT_PREFIX:
2303 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2304 break;
2305 case SUBJECT_SUFFIX: {
2306 int subject_length = part.data;
2307 if (match_to < subject_length) {
2308 builder->AddSubjectSlice(match_to, subject_length);
2309 }
2310 break;
2311 }
2312 case SUBJECT_CAPTURE: {
2313 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002314 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002315 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2316 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2317 if (from >= 0 && to > from) {
2318 builder->AddSubjectSlice(from, to);
2319 }
2320 break;
2321 }
2322 case REPLACEMENT_SUBSTRING:
2323 case REPLACEMENT_STRING:
2324 builder->AddString(replacement_substrings_[part.data]);
2325 break;
2326 default:
2327 UNREACHABLE();
2328 }
2329 }
2330}
2331
2332
2333
lrn@chromium.org303ada72010-10-27 09:33:13 +00002334MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
2335 String* subject,
2336 JSRegExp* regexp,
2337 String* replacement,
2338 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002339 ASSERT(subject->IsFlat());
2340 ASSERT(replacement->IsFlat());
2341
2342 HandleScope handles;
2343
2344 int length = subject->length();
2345 Handle<String> subject_handle(subject);
2346 Handle<JSRegExp> regexp_handle(regexp);
2347 Handle<String> replacement_handle(replacement);
2348 Handle<JSArray> last_match_info_handle(last_match_info);
2349 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2350 subject_handle,
2351 0,
2352 last_match_info_handle);
2353 if (match.is_null()) {
2354 return Failure::Exception();
2355 }
2356 if (match->IsNull()) {
2357 return *subject_handle;
2358 }
2359
2360 int capture_count = regexp_handle->CaptureCount();
2361
2362 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002363 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002364 CompiledReplacement compiled_replacement;
2365 compiled_replacement.Compile(replacement_handle,
2366 capture_count,
2367 length);
2368
2369 bool is_global = regexp_handle->GetFlags().is_global();
2370
2371 // Guessing the number of parts that the final result string is built
2372 // from. Global regexps can match any number of times, so we guess
2373 // conservatively.
2374 int expected_parts =
2375 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
2376 ReplacementStringBuilder builder(subject_handle, expected_parts);
2377
2378 // Index of end of last match.
2379 int prev = 0;
2380
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002381 // Number of parts added by compiled replacement plus preceeding
2382 // string and possibly suffix after last match. It is possible for
2383 // all components to use two elements when encoded as two smis.
2384 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002385 bool matched = true;
2386 do {
2387 ASSERT(last_match_info_handle->HasFastElements());
2388 // Increase the capacity of the builder before entering local handle-scope,
2389 // so its internal buffer can safely allocate a new handle if it grows.
2390 builder.EnsureCapacity(parts_added_per_loop);
2391
2392 HandleScope loop_scope;
2393 int start, end;
2394 {
2395 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002396 FixedArray* match_info_array =
2397 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002398
2399 ASSERT_EQ(capture_count * 2 + 2,
2400 RegExpImpl::GetLastCaptureCount(match_info_array));
2401 start = RegExpImpl::GetCapture(match_info_array, 0);
2402 end = RegExpImpl::GetCapture(match_info_array, 1);
2403 }
2404
2405 if (prev < start) {
2406 builder.AddSubjectSlice(prev, start);
2407 }
2408 compiled_replacement.Apply(&builder,
2409 start,
2410 end,
2411 last_match_info_handle);
2412 prev = end;
2413
2414 // Only continue checking for global regexps.
2415 if (!is_global) break;
2416
2417 // Continue from where the match ended, unless it was an empty match.
2418 int next = end;
2419 if (start == end) {
2420 next = end + 1;
2421 if (next > length) break;
2422 }
2423
2424 match = RegExpImpl::Exec(regexp_handle,
2425 subject_handle,
2426 next,
2427 last_match_info_handle);
2428 if (match.is_null()) {
2429 return Failure::Exception();
2430 }
2431 matched = !match->IsNull();
2432 } while (matched);
2433
2434 if (prev < length) {
2435 builder.AddSubjectSlice(prev, length);
2436 }
2437
2438 return *(builder.ToString());
2439}
2440
2441
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002442template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002443MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
2444 String* subject,
2445 JSRegExp* regexp,
2446 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002447 ASSERT(subject->IsFlat());
2448
2449 HandleScope handles;
2450
2451 Handle<String> subject_handle(subject);
2452 Handle<JSRegExp> regexp_handle(regexp);
2453 Handle<JSArray> last_match_info_handle(last_match_info);
2454 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2455 subject_handle,
2456 0,
2457 last_match_info_handle);
2458 if (match.is_null()) return Failure::Exception();
2459 if (match->IsNull()) return *subject_handle;
2460
2461 ASSERT(last_match_info_handle->HasFastElements());
2462
2463 HandleScope loop_scope;
2464 int start, end;
2465 {
2466 AssertNoAllocation match_info_array_is_not_in_a_handle;
2467 FixedArray* match_info_array =
2468 FixedArray::cast(last_match_info_handle->elements());
2469
2470 start = RegExpImpl::GetCapture(match_info_array, 0);
2471 end = RegExpImpl::GetCapture(match_info_array, 1);
2472 }
2473
2474 int length = subject->length();
2475 int new_length = length - (end - start);
2476 if (new_length == 0) {
2477 return Heap::empty_string();
2478 }
2479 Handle<ResultSeqString> answer;
2480 if (ResultSeqString::kHasAsciiEncoding) {
2481 answer =
2482 Handle<ResultSeqString>::cast(Factory::NewRawAsciiString(new_length));
2483 } else {
2484 answer =
2485 Handle<ResultSeqString>::cast(Factory::NewRawTwoByteString(new_length));
2486 }
2487
2488 // If the regexp isn't global, only match once.
2489 if (!regexp_handle->GetFlags().is_global()) {
2490 if (start > 0) {
2491 String::WriteToFlat(*subject_handle,
2492 answer->GetChars(),
2493 0,
2494 start);
2495 }
2496 if (end < length) {
2497 String::WriteToFlat(*subject_handle,
2498 answer->GetChars() + start,
2499 end,
2500 length);
2501 }
2502 return *answer;
2503 }
2504
2505 int prev = 0; // Index of end of last match.
2506 int next = 0; // Start of next search (prev unless last match was empty).
2507 int position = 0;
2508
2509 do {
2510 if (prev < start) {
2511 // Add substring subject[prev;start] to answer string.
2512 String::WriteToFlat(*subject_handle,
2513 answer->GetChars() + position,
2514 prev,
2515 start);
2516 position += start - prev;
2517 }
2518 prev = end;
2519 next = end;
2520 // Continue from where the match ended, unless it was an empty match.
2521 if (start == end) {
2522 next++;
2523 if (next > length) break;
2524 }
2525 match = RegExpImpl::Exec(regexp_handle,
2526 subject_handle,
2527 next,
2528 last_match_info_handle);
2529 if (match.is_null()) return Failure::Exception();
2530 if (match->IsNull()) break;
2531
2532 ASSERT(last_match_info_handle->HasFastElements());
2533 HandleScope loop_scope;
2534 {
2535 AssertNoAllocation match_info_array_is_not_in_a_handle;
2536 FixedArray* match_info_array =
2537 FixedArray::cast(last_match_info_handle->elements());
2538 start = RegExpImpl::GetCapture(match_info_array, 0);
2539 end = RegExpImpl::GetCapture(match_info_array, 1);
2540 }
2541 } while (true);
2542
2543 if (prev < length) {
2544 // Add substring subject[prev;length] to answer string.
2545 String::WriteToFlat(*subject_handle,
2546 answer->GetChars() + position,
2547 prev,
2548 length);
2549 position += length - prev;
2550 }
2551
2552 if (position == 0) {
2553 return Heap::empty_string();
2554 }
2555
2556 // Shorten string and fill
2557 int string_size = ResultSeqString::SizeFor(position);
2558 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2559 int delta = allocated_string_size - string_size;
2560
2561 answer->set_length(position);
2562 if (delta == 0) return *answer;
2563
2564 Address end_of_string = answer->address() + string_size;
2565 Heap::CreateFillerObjectAt(end_of_string, delta);
2566
2567 return *answer;
2568}
2569
2570
lrn@chromium.org303ada72010-10-27 09:33:13 +00002571static MaybeObject* Runtime_StringReplaceRegExpWithString(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002572 ASSERT(args.length() == 4);
2573
2574 CONVERT_CHECKED(String, subject, args[0]);
2575 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002576 Object* flat_subject;
2577 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2578 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2579 return maybe_flat_subject;
2580 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002581 }
2582 subject = String::cast(flat_subject);
2583 }
2584
2585 CONVERT_CHECKED(String, replacement, args[2]);
2586 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002587 Object* flat_replacement;
2588 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2589 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2590 return maybe_flat_replacement;
2591 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002592 }
2593 replacement = String::cast(flat_replacement);
2594 }
2595
2596 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2597 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2598
2599 ASSERT(last_match_info->HasFastElements());
2600
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002601 if (replacement->length() == 0) {
2602 if (subject->HasOnlyAsciiChars()) {
2603 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
2604 subject, regexp, last_match_info);
2605 } else {
2606 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
2607 subject, regexp, last_match_info);
2608 }
2609 }
2610
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002611 return StringReplaceRegExpWithString(subject,
2612 regexp,
2613 replacement,
2614 last_match_info);
2615}
2616
2617
ager@chromium.org7c537e22008-10-16 08:43:32 +00002618// Perform string match of pattern on subject, starting at start index.
2619// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002620// and should check that pat->length() + start_index <= sub->length().
ager@chromium.org7c537e22008-10-16 08:43:32 +00002621int Runtime::StringMatch(Handle<String> sub,
2622 Handle<String> pat,
2623 int start_index) {
2624 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002625 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002626
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002627 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002628 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002629
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002630 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002631 if (start_index + pattern_length > subject_length) return -1;
2632
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002633 if (!sub->IsFlat()) FlattenString(sub);
2634 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002635
ager@chromium.org7c537e22008-10-16 08:43:32 +00002636 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002637 // Extract flattened substrings of cons strings before determining asciiness.
2638 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002639 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002640 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002641 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002642
ager@chromium.org7c537e22008-10-16 08:43:32 +00002643 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002644 if (seq_pat->IsAsciiRepresentation()) {
2645 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2646 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002647 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002648 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002649 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002650 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002651 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2652 if (seq_sub->IsAsciiRepresentation()) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002653 return SearchString(seq_sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002654 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002655 return SearchString(seq_sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002656}
2657
2658
lrn@chromium.org303ada72010-10-27 09:33:13 +00002659static MaybeObject* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002660 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002661 ASSERT(args.length() == 3);
2662
ager@chromium.org7c537e22008-10-16 08:43:32 +00002663 CONVERT_ARG_CHECKED(String, sub, 0);
2664 CONVERT_ARG_CHECKED(String, pat, 1);
2665
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002666 Object* index = args[2];
2667 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002668 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002669
ager@chromium.org870a0b62008-11-04 11:43:05 +00002670 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00002671 int position = Runtime::StringMatch(sub, pat, start_index);
2672 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002673}
2674
2675
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002676template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002677static int StringMatchBackwards(Vector<const schar> subject,
2678 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002679 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002680 int pattern_length = pattern.length();
2681 ASSERT(pattern_length >= 1);
2682 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002683
2684 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002685 for (int i = 0; i < pattern_length; i++) {
2686 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002687 if (c > String::kMaxAsciiCharCode) {
2688 return -1;
2689 }
2690 }
2691 }
2692
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002693 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002694 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002695 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002696 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002697 while (j < pattern_length) {
2698 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002699 break;
2700 }
2701 j++;
2702 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002703 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002704 return i;
2705 }
2706 }
2707 return -1;
2708}
2709
lrn@chromium.org303ada72010-10-27 09:33:13 +00002710static MaybeObject* Runtime_StringLastIndexOf(Arguments args) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002711 HandleScope scope; // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002712 ASSERT(args.length() == 3);
2713
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002714 CONVERT_ARG_CHECKED(String, sub, 0);
2715 CONVERT_ARG_CHECKED(String, pat, 1);
2716
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002717 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002718 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002719 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002720
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002721 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002722 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002723
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002724 if (start_index + pat_length > sub_length) {
2725 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002726 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002727
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002728 if (pat_length == 0) {
2729 return Smi::FromInt(start_index);
2730 }
2731
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002732 if (!sub->IsFlat()) FlattenString(sub);
2733 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002734
2735 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2736
2737 int position = -1;
2738
2739 if (pat->IsAsciiRepresentation()) {
2740 Vector<const char> pat_vector = pat->ToAsciiVector();
2741 if (sub->IsAsciiRepresentation()) {
2742 position = StringMatchBackwards(sub->ToAsciiVector(),
2743 pat_vector,
2744 start_index);
2745 } else {
2746 position = StringMatchBackwards(sub->ToUC16Vector(),
2747 pat_vector,
2748 start_index);
2749 }
2750 } else {
2751 Vector<const uc16> pat_vector = pat->ToUC16Vector();
2752 if (sub->IsAsciiRepresentation()) {
2753 position = StringMatchBackwards(sub->ToAsciiVector(),
2754 pat_vector,
2755 start_index);
2756 } else {
2757 position = StringMatchBackwards(sub->ToUC16Vector(),
2758 pat_vector,
2759 start_index);
2760 }
2761 }
2762
2763 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002764}
2765
2766
lrn@chromium.org303ada72010-10-27 09:33:13 +00002767static MaybeObject* Runtime_StringLocaleCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002768 NoHandleAllocation ha;
2769 ASSERT(args.length() == 2);
2770
2771 CONVERT_CHECKED(String, str1, args[0]);
2772 CONVERT_CHECKED(String, str2, args[1]);
2773
2774 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002775 int str1_length = str1->length();
2776 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002777
2778 // Decide trivial cases without flattening.
2779 if (str1_length == 0) {
2780 if (str2_length == 0) return Smi::FromInt(0); // Equal.
2781 return Smi::FromInt(-str2_length);
2782 } else {
2783 if (str2_length == 0) return Smi::FromInt(str1_length);
2784 }
2785
2786 int end = str1_length < str2_length ? str1_length : str2_length;
2787
2788 // No need to flatten if we are going to find the answer on the first
2789 // character. At this point we know there is at least one character
2790 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002791 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002792 if (d != 0) return Smi::FromInt(d);
2793
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002794 str1->TryFlatten();
2795 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002796
2797 static StringInputBuffer buf1;
2798 static StringInputBuffer buf2;
2799
2800 buf1.Reset(str1);
2801 buf2.Reset(str2);
2802
2803 for (int i = 0; i < end; i++) {
2804 uint16_t char1 = buf1.GetNext();
2805 uint16_t char2 = buf2.GetNext();
2806 if (char1 != char2) return Smi::FromInt(char1 - char2);
2807 }
2808
2809 return Smi::FromInt(str1_length - str2_length);
2810}
2811
2812
lrn@chromium.org303ada72010-10-27 09:33:13 +00002813static MaybeObject* Runtime_SubString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002814 NoHandleAllocation ha;
2815 ASSERT(args.length() == 3);
2816
2817 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002818 Object* from = args[1];
2819 Object* to = args[2];
2820 int start, end;
2821 // We have a fast integer-only case here to avoid a conversion to double in
2822 // the common case where from and to are Smis.
2823 if (from->IsSmi() && to->IsSmi()) {
2824 start = Smi::cast(from)->value();
2825 end = Smi::cast(to)->value();
2826 } else {
2827 CONVERT_DOUBLE_CHECKED(from_number, from);
2828 CONVERT_DOUBLE_CHECKED(to_number, to);
2829 start = FastD2I(from_number);
2830 end = FastD2I(to_number);
2831 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002832 RUNTIME_ASSERT(end >= start);
2833 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002834 RUNTIME_ASSERT(end <= value->length());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002835 Counters::sub_string_runtime.Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002836 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002837}
2838
2839
lrn@chromium.org303ada72010-10-27 09:33:13 +00002840static MaybeObject* Runtime_StringMatch(Arguments args) {
ager@chromium.org41826e72009-03-30 13:30:57 +00002841 ASSERT_EQ(3, args.length());
2842
2843 CONVERT_ARG_CHECKED(String, subject, 0);
2844 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
2845 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
2846 HandleScope handles;
2847
2848 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
2849
2850 if (match.is_null()) {
2851 return Failure::Exception();
2852 }
2853 if (match->IsNull()) {
2854 return Heap::null_value();
2855 }
2856 int length = subject->length();
2857
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002858 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00002859 ZoneList<int> offsets(8);
2860 do {
2861 int start;
2862 int end;
2863 {
2864 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002865 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00002866 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
2867 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
2868 }
2869 offsets.Add(start);
2870 offsets.Add(end);
2871 int index = start < end ? end : end + 1;
2872 if (index > length) break;
2873 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
2874 if (match.is_null()) {
2875 return Failure::Exception();
2876 }
2877 } while (!match->IsNull());
2878 int matches = offsets.length() / 2;
2879 Handle<FixedArray> elements = Factory::NewFixedArray(matches);
2880 for (int i = 0; i < matches ; i++) {
2881 int from = offsets.at(i * 2);
2882 int to = offsets.at(i * 2 + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002883 Handle<String> match = Factory::NewSubString(subject, from, to);
2884 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00002885 }
2886 Handle<JSArray> result = Factory::NewJSArrayWithElements(elements);
2887 result->set_length(Smi::FromInt(matches));
2888 return *result;
2889}
2890
2891
lrn@chromium.org25156de2010-04-06 13:10:27 +00002892// Two smis before and after the match, for very long strings.
2893const int kMaxBuilderEntriesPerRegExpMatch = 5;
2894
2895
2896static void SetLastMatchInfoNoCaptures(Handle<String> subject,
2897 Handle<JSArray> last_match_info,
2898 int match_start,
2899 int match_end) {
2900 // Fill last_match_info with a single capture.
2901 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
2902 AssertNoAllocation no_gc;
2903 FixedArray* elements = FixedArray::cast(last_match_info->elements());
2904 RegExpImpl::SetLastCaptureCount(elements, 2);
2905 RegExpImpl::SetLastInput(elements, *subject);
2906 RegExpImpl::SetLastSubject(elements, *subject);
2907 RegExpImpl::SetCapture(elements, 0, match_start);
2908 RegExpImpl::SetCapture(elements, 1, match_end);
2909}
2910
2911
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002912template <typename SubjectChar, typename PatternChar>
2913static bool SearchStringMultiple(Vector<const SubjectChar> subject,
2914 Vector<const PatternChar> pattern,
2915 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002916 FixedArrayBuilder* builder,
2917 int* match_pos) {
2918 int pos = *match_pos;
2919 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002920 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002921 int max_search_start = subject_length - pattern_length;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002922 StringSearch<PatternChar, SubjectChar> search(pattern);
2923 while (pos <= max_search_start) {
2924 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
2925 *match_pos = pos;
2926 return false;
2927 }
2928 // Position of end of previous match.
2929 int match_end = pos + pattern_length;
2930 int new_pos = search.Search(subject, match_end);
2931 if (new_pos >= 0) {
2932 // A match.
2933 if (new_pos > match_end) {
2934 ReplacementStringBuilder::AddSubjectSlice(builder,
2935 match_end,
2936 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002937 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002938 pos = new_pos;
2939 builder->Add(pattern_string);
2940 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002941 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002942 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002943 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002944
lrn@chromium.org25156de2010-04-06 13:10:27 +00002945 if (pos < max_search_start) {
2946 ReplacementStringBuilder::AddSubjectSlice(builder,
2947 pos + pattern_length,
2948 subject_length);
2949 }
2950 *match_pos = pos;
2951 return true;
2952}
2953
2954
2955static bool SearchStringMultiple(Handle<String> subject,
2956 Handle<String> pattern,
2957 Handle<JSArray> last_match_info,
2958 FixedArrayBuilder* builder) {
2959 ASSERT(subject->IsFlat());
2960 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002961
2962 // Treating as if a previous match was before first character.
2963 int match_pos = -pattern->length();
2964
2965 for (;;) { // Break when search complete.
2966 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
2967 AssertNoAllocation no_gc;
2968 if (subject->IsAsciiRepresentation()) {
2969 Vector<const char> subject_vector = subject->ToAsciiVector();
2970 if (pattern->IsAsciiRepresentation()) {
2971 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002972 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002973 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002974 builder,
2975 &match_pos)) break;
2976 } else {
2977 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002978 pattern->ToUC16Vector(),
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 }
2983 } else {
2984 Vector<const uc16> subject_vector = subject->ToUC16Vector();
2985 if (pattern->IsAsciiRepresentation()) {
2986 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002987 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002988 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002989 builder,
2990 &match_pos)) break;
2991 } else {
2992 if (SearchStringMultiple(subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002993 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00002994 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002995 builder,
2996 &match_pos)) break;
2997 }
2998 }
2999 }
3000
3001 if (match_pos >= 0) {
3002 SetLastMatchInfoNoCaptures(subject,
3003 last_match_info,
3004 match_pos,
3005 match_pos + pattern->length());
3006 return true;
3007 }
3008 return false; // No matches at all.
3009}
3010
3011
3012static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
3013 Handle<String> subject,
3014 Handle<JSRegExp> regexp,
3015 Handle<JSArray> last_match_array,
3016 FixedArrayBuilder* builder) {
3017 ASSERT(subject->IsFlat());
3018 int match_start = -1;
3019 int match_end = 0;
3020 int pos = 0;
3021 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3022 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3023
3024 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003025 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003026 int subject_length = subject->length();
3027
3028 for (;;) { // Break on failure, return on exception.
3029 RegExpImpl::IrregexpResult result =
3030 RegExpImpl::IrregexpExecOnce(regexp,
3031 subject,
3032 pos,
3033 register_vector);
3034 if (result == RegExpImpl::RE_SUCCESS) {
3035 match_start = register_vector[0];
3036 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3037 if (match_end < match_start) {
3038 ReplacementStringBuilder::AddSubjectSlice(builder,
3039 match_end,
3040 match_start);
3041 }
3042 match_end = register_vector[1];
3043 HandleScope loop_scope;
3044 builder->Add(*Factory::NewSubString(subject, match_start, match_end));
3045 if (match_start != match_end) {
3046 pos = match_end;
3047 } else {
3048 pos = match_end + 1;
3049 if (pos > subject_length) break;
3050 }
3051 } else if (result == RegExpImpl::RE_FAILURE) {
3052 break;
3053 } else {
3054 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3055 return result;
3056 }
3057 }
3058
3059 if (match_start >= 0) {
3060 if (match_end < subject_length) {
3061 ReplacementStringBuilder::AddSubjectSlice(builder,
3062 match_end,
3063 subject_length);
3064 }
3065 SetLastMatchInfoNoCaptures(subject,
3066 last_match_array,
3067 match_start,
3068 match_end);
3069 return RegExpImpl::RE_SUCCESS;
3070 } else {
3071 return RegExpImpl::RE_FAILURE; // No matches at all.
3072 }
3073}
3074
3075
3076static RegExpImpl::IrregexpResult SearchRegExpMultiple(
3077 Handle<String> subject,
3078 Handle<JSRegExp> regexp,
3079 Handle<JSArray> last_match_array,
3080 FixedArrayBuilder* builder) {
3081
3082 ASSERT(subject->IsFlat());
3083 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3084 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3085
3086 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003087 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003088
3089 RegExpImpl::IrregexpResult result =
3090 RegExpImpl::IrregexpExecOnce(regexp,
3091 subject,
3092 0,
3093 register_vector);
3094
3095 int capture_count = regexp->CaptureCount();
3096 int subject_length = subject->length();
3097
3098 // Position to search from.
3099 int pos = 0;
3100 // End of previous match. Differs from pos if match was empty.
3101 int match_end = 0;
3102 if (result == RegExpImpl::RE_SUCCESS) {
3103 // Need to keep a copy of the previous match for creating last_match_info
3104 // at the end, so we have two vectors that we swap between.
3105 OffsetsVector registers2(required_registers);
3106 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3107
3108 do {
3109 int match_start = register_vector[0];
3110 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3111 if (match_end < match_start) {
3112 ReplacementStringBuilder::AddSubjectSlice(builder,
3113 match_end,
3114 match_start);
3115 }
3116 match_end = register_vector[1];
3117
3118 {
3119 // Avoid accumulating new handles inside loop.
3120 HandleScope temp_scope;
3121 // Arguments array to replace function is match, captures, index and
3122 // subject, i.e., 3 + capture count in total.
3123 Handle<FixedArray> elements = Factory::NewFixedArray(3 + capture_count);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003124 Handle<String> match = Factory::NewSubString(subject,
3125 match_start,
3126 match_end);
3127 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003128 for (int i = 1; i <= capture_count; i++) {
3129 int start = register_vector[i * 2];
3130 if (start >= 0) {
3131 int end = register_vector[i * 2 + 1];
3132 ASSERT(start <= end);
3133 Handle<String> substring = Factory::NewSubString(subject,
3134 start,
3135 end);
3136 elements->set(i, *substring);
3137 } else {
3138 ASSERT(register_vector[i * 2 + 1] < 0);
3139 elements->set(i, Heap::undefined_value());
3140 }
3141 }
3142 elements->set(capture_count + 1, Smi::FromInt(match_start));
3143 elements->set(capture_count + 2, *subject);
3144 builder->Add(*Factory::NewJSArrayWithElements(elements));
3145 }
3146 // Swap register vectors, so the last successful match is in
3147 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003148 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003149 prev_register_vector = register_vector;
3150 register_vector = tmp;
3151
3152 if (match_end > match_start) {
3153 pos = match_end;
3154 } else {
3155 pos = match_end + 1;
3156 if (pos > subject_length) {
3157 break;
3158 }
3159 }
3160
3161 result = RegExpImpl::IrregexpExecOnce(regexp,
3162 subject,
3163 pos,
3164 register_vector);
3165 } while (result == RegExpImpl::RE_SUCCESS);
3166
3167 if (result != RegExpImpl::RE_EXCEPTION) {
3168 // Finished matching, with at least one match.
3169 if (match_end < subject_length) {
3170 ReplacementStringBuilder::AddSubjectSlice(builder,
3171 match_end,
3172 subject_length);
3173 }
3174
3175 int last_match_capture_count = (capture_count + 1) * 2;
3176 int last_match_array_size =
3177 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3178 last_match_array->EnsureSize(last_match_array_size);
3179 AssertNoAllocation no_gc;
3180 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3181 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3182 RegExpImpl::SetLastSubject(elements, *subject);
3183 RegExpImpl::SetLastInput(elements, *subject);
3184 for (int i = 0; i < last_match_capture_count; i++) {
3185 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3186 }
3187 return RegExpImpl::RE_SUCCESS;
3188 }
3189 }
3190 // No matches at all, return failure or exception result directly.
3191 return result;
3192}
3193
3194
lrn@chromium.org303ada72010-10-27 09:33:13 +00003195static MaybeObject* Runtime_RegExpExecMultiple(Arguments args) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003196 ASSERT(args.length() == 4);
3197 HandleScope handles;
3198
3199 CONVERT_ARG_CHECKED(String, subject, 1);
3200 if (!subject->IsFlat()) { FlattenString(subject); }
3201 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3202 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3203 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3204
3205 ASSERT(last_match_info->HasFastElements());
3206 ASSERT(regexp->GetFlags().is_global());
3207 Handle<FixedArray> result_elements;
3208 if (result_array->HasFastElements()) {
3209 result_elements =
3210 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3211 } else {
3212 result_elements = Factory::NewFixedArrayWithHoles(16);
3213 }
3214 FixedArrayBuilder builder(result_elements);
3215
3216 if (regexp->TypeTag() == JSRegExp::ATOM) {
3217 Handle<String> pattern(
3218 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003219 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003220 if (SearchStringMultiple(subject, pattern, last_match_info, &builder)) {
3221 return *builder.ToJSArray(result_array);
3222 }
3223 return Heap::null_value();
3224 }
3225
3226 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3227
3228 RegExpImpl::IrregexpResult result;
3229 if (regexp->CaptureCount() == 0) {
3230 result = SearchRegExpNoCaptureMultiple(subject,
3231 regexp,
3232 last_match_info,
3233 &builder);
3234 } else {
3235 result = SearchRegExpMultiple(subject, regexp, last_match_info, &builder);
3236 }
3237 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
3238 if (result == RegExpImpl::RE_FAILURE) return Heap::null_value();
3239 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3240 return Failure::Exception();
3241}
3242
3243
lrn@chromium.org303ada72010-10-27 09:33:13 +00003244static MaybeObject* Runtime_NumberToRadixString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003245 NoHandleAllocation ha;
3246 ASSERT(args.length() == 2);
3247
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003248 // Fast case where the result is a one character string.
3249 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3250 int value = Smi::cast(args[0])->value();
3251 int radix = Smi::cast(args[1])->value();
3252 if (value >= 0 && value < radix) {
3253 RUNTIME_ASSERT(radix <= 36);
3254 // Character array used for conversion.
3255 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
3256 return Heap::LookupSingleCharacterStringFromCode(kCharTable[value]);
3257 }
3258 }
3259
3260 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003261 CONVERT_DOUBLE_CHECKED(value, args[0]);
3262 if (isnan(value)) {
3263 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3264 }
3265 if (isinf(value)) {
3266 if (value < 0) {
3267 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3268 }
3269 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3270 }
3271 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3272 int radix = FastD2I(radix_number);
3273 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3274 char* str = DoubleToRadixCString(value, radix);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003275 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003276 DeleteArray(str);
3277 return result;
3278}
3279
3280
lrn@chromium.org303ada72010-10-27 09:33:13 +00003281static MaybeObject* Runtime_NumberToFixed(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003282 NoHandleAllocation ha;
3283 ASSERT(args.length() == 2);
3284
3285 CONVERT_DOUBLE_CHECKED(value, args[0]);
3286 if (isnan(value)) {
3287 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3288 }
3289 if (isinf(value)) {
3290 if (value < 0) {
3291 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3292 }
3293 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3294 }
3295 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3296 int f = FastD2I(f_number);
3297 RUNTIME_ASSERT(f >= 0);
3298 char* str = DoubleToFixedCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003299 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003300 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003301 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003302}
3303
3304
lrn@chromium.org303ada72010-10-27 09:33:13 +00003305static MaybeObject* Runtime_NumberToExponential(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003306 NoHandleAllocation ha;
3307 ASSERT(args.length() == 2);
3308
3309 CONVERT_DOUBLE_CHECKED(value, args[0]);
3310 if (isnan(value)) {
3311 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3312 }
3313 if (isinf(value)) {
3314 if (value < 0) {
3315 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3316 }
3317 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3318 }
3319 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3320 int f = FastD2I(f_number);
3321 RUNTIME_ASSERT(f >= -1 && f <= 20);
3322 char* str = DoubleToExponentialCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003323 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003324 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003325 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003326}
3327
3328
lrn@chromium.org303ada72010-10-27 09:33:13 +00003329static MaybeObject* Runtime_NumberToPrecision(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003330 NoHandleAllocation ha;
3331 ASSERT(args.length() == 2);
3332
3333 CONVERT_DOUBLE_CHECKED(value, args[0]);
3334 if (isnan(value)) {
3335 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
3336 }
3337 if (isinf(value)) {
3338 if (value < 0) {
3339 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
3340 }
3341 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
3342 }
3343 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3344 int f = FastD2I(f_number);
3345 RUNTIME_ASSERT(f >= 1 && f <= 21);
3346 char* str = DoubleToPrecisionCString(value, f);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003347 MaybeObject* result = Heap::AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003348 DeleteArray(str);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003349 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003350}
3351
3352
3353// Returns a single character string where first character equals
3354// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003355static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003356 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003357 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003358 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003359 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003360 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003361 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003362}
3363
3364
lrn@chromium.org303ada72010-10-27 09:33:13 +00003365MaybeObject* Runtime::GetElementOrCharAt(Handle<Object> object,
3366 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003367 // Handle [] indexing on Strings
3368 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003369 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3370 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003371 }
3372
3373 // Handle [] indexing on String objects
3374 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003375 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3376 Handle<Object> result =
3377 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3378 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003379 }
3380
3381 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003382 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003383 return prototype->GetElement(index);
3384 }
3385
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003386 return GetElement(object, index);
3387}
3388
3389
lrn@chromium.org303ada72010-10-27 09:33:13 +00003390MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003391 return object->GetElement(index);
3392}
3393
3394
lrn@chromium.org303ada72010-10-27 09:33:13 +00003395MaybeObject* Runtime::GetObjectProperty(Handle<Object> object,
3396 Handle<Object> key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003397 HandleScope scope;
3398
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003399 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003400 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003401 Handle<Object> error =
3402 Factory::NewTypeError("non_object_property_load",
3403 HandleVector(args, 2));
3404 return Top::Throw(*error);
3405 }
3406
3407 // Check if the given key is an array index.
3408 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003409 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003410 return GetElementOrCharAt(object, index);
3411 }
3412
3413 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003414 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003415 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003416 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003417 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003418 bool has_pending_exception = false;
3419 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003420 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003421 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003422 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003423 }
3424
ager@chromium.org32912102009-01-16 10:38:43 +00003425 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003426 // the element if so.
3427 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003428 return GetElementOrCharAt(object, index);
3429 } else {
3430 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003431 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003432 }
3433}
3434
3435
lrn@chromium.org303ada72010-10-27 09:33:13 +00003436static MaybeObject* Runtime_GetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003437 NoHandleAllocation ha;
3438 ASSERT(args.length() == 2);
3439
3440 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003441 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003442
3443 return Runtime::GetObjectProperty(object, key);
3444}
3445
3446
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003447// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003448static MaybeObject* Runtime_KeyedGetProperty(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003449 NoHandleAllocation ha;
3450 ASSERT(args.length() == 2);
3451
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003452 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003453 // itself.
3454 //
3455 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003456 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003457 // global proxy object never has properties. This is the case
3458 // because the global proxy object forwards everything to its hidden
3459 // prototype including local lookups.
3460 //
3461 // Additionally, we need to make sure that we do not cache results
3462 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003463 if (args[0]->IsJSObject() &&
3464 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003465 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003466 args[1]->IsString()) {
3467 JSObject* receiver = JSObject::cast(args[0]);
3468 String* key = String::cast(args[1]);
3469 if (receiver->HasFastProperties()) {
3470 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003471 Map* receiver_map = receiver->map();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003472 int offset = KeyedLookupCache::Lookup(receiver_map, key);
3473 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003474 Object* value = receiver->FastPropertyAt(offset);
3475 return value->IsTheHole() ? Heap::undefined_value() : value;
3476 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003477 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003478 LookupResult result;
3479 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003480 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003481 int offset = result.GetFieldIndex();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003482 KeyedLookupCache::Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003483 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003484 }
3485 } else {
3486 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003487 StringDictionary* dictionary = receiver->property_dictionary();
3488 int entry = dictionary->FindEntry(key);
3489 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003490 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003491 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003492 if (!receiver->IsGlobalObject()) return value;
3493 value = JSGlobalPropertyCell::cast(value)->value();
3494 if (!value->IsTheHole()) return value;
3495 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003496 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003497 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003498 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3499 // Fast case for string indexing using [] with a smi index.
3500 HandleScope scope;
3501 Handle<String> str = args.at<String>(0);
3502 int index = Smi::cast(args[1])->value();
3503 Handle<Object> result = GetCharAt(str, index);
3504 return *result;
ager@chromium.org7c537e22008-10-16 08:43:32 +00003505 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003506
3507 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003508 return Runtime::GetObjectProperty(args.at<Object>(0),
3509 args.at<Object>(1));
3510}
3511
3512
lrn@chromium.org303ada72010-10-27 09:33:13 +00003513static MaybeObject* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003514 ASSERT(args.length() == 5);
3515 HandleScope scope;
3516 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3517 CONVERT_CHECKED(String, name, args[1]);
3518 CONVERT_CHECKED(Smi, flag_setter, args[2]);
3519 CONVERT_CHECKED(JSFunction, fun, args[3]);
3520 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3521 int unchecked = flag_attr->value();
3522 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3523 RUNTIME_ASSERT(!obj->IsNull());
3524 LookupResult result;
3525 obj->LocalLookupRealNamedProperty(name, &result);
3526
3527 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3528 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3529 // delete it to avoid running into trouble in DefineAccessor, which
3530 // handles this incorrectly if the property is readonly (does nothing)
3531 if (result.IsProperty() &&
3532 (result.type() == FIELD || result.type() == NORMAL
3533 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003534 Object* ok;
3535 { MaybeObject* maybe_ok =
3536 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3537 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3538 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003539 }
3540 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3541}
3542
lrn@chromium.org303ada72010-10-27 09:33:13 +00003543static MaybeObject* Runtime_DefineOrRedefineDataProperty(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003544 ASSERT(args.length() == 4);
3545 HandleScope scope;
3546 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3547 CONVERT_ARG_CHECKED(String, name, 1);
3548 Handle<Object> obj_value = args.at<Object>(2);
3549
3550 CONVERT_CHECKED(Smi, flag, args[3]);
3551 int unchecked = flag->value();
3552 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3553
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003554 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3555
3556 // Check if this is an element.
3557 uint32_t index;
3558 bool is_element = name->AsArrayIndex(&index);
3559
3560 // Special case for elements if any of the flags are true.
3561 // If elements are in fast case we always implicitly assume that:
3562 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3563 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3564 is_element) {
3565 // Normalize the elements to enable attributes on the property.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003566 NormalizeElements(js_object);
3567 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003568 // Make sure that we never go back to fast case.
3569 dictionary->set_requires_slow_elements();
3570 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003571 NumberDictionarySet(dictionary, index, obj_value, details);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003572 }
3573
ager@chromium.org5c838252010-02-19 08:53:10 +00003574 LookupResult result;
3575 js_object->LocalLookupRealNamedProperty(*name, &result);
3576
ager@chromium.org5c838252010-02-19 08:53:10 +00003577 // Take special care when attributes are different and there is already
3578 // a property. For simplicity we normalize the property which enables us
3579 // to not worry about changing the instance_descriptor and creating a new
3580 // map. The current version of SetObjectProperty does not handle attributes
3581 // correctly in the case where a property is a field and is reset with
3582 // new attributes.
3583 if (result.IsProperty() && attr != result.GetAttributes()) {
3584 // New attributes - normalize to avoid writing to instance descriptor
lrn@chromium.org303ada72010-10-27 09:33:13 +00003585 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003586 // Use IgnoreAttributes version since a readonly property may be
3587 // overridden and SetProperty does not allow this.
3588 return js_object->IgnoreAttributesAndSetLocalProperty(*name,
3589 *obj_value,
3590 attr);
3591 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003592
ager@chromium.org5c838252010-02-19 08:53:10 +00003593 return Runtime::SetObjectProperty(js_object, name, obj_value, attr);
3594}
3595
3596
lrn@chromium.org303ada72010-10-27 09:33:13 +00003597MaybeObject* Runtime::SetObjectProperty(Handle<Object> object,
3598 Handle<Object> key,
3599 Handle<Object> value,
3600 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003601 HandleScope scope;
3602
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003603 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003604 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003605 Handle<Object> error =
3606 Factory::NewTypeError("non_object_property_store",
3607 HandleVector(args, 2));
3608 return Top::Throw(*error);
3609 }
3610
3611 // If the object isn't a JavaScript object, we ignore the store.
3612 if (!object->IsJSObject()) return *value;
3613
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003614 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3615
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003616 // Check if the given key is an array index.
3617 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003618 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003619 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3620 // of a string using [] notation. We need to support this too in
3621 // JavaScript.
3622 // In the case of a String object we just need to redirect the assignment to
3623 // the underlying string if the index is in range. Since the underlying
3624 // string does nothing with the assignment then we can ignore such
3625 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003626 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003627 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003628 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003629
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003630 Handle<Object> result = SetElement(js_object, index, value);
3631 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003632 return *value;
3633 }
3634
3635 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003636 Handle<Object> result;
3637 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003638 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003639 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003640 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003641 key_string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003642 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003643 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003644 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003645 return *value;
3646 }
3647
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003648 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003649 bool has_pending_exception = false;
3650 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3651 if (has_pending_exception) return Failure::Exception();
3652 Handle<String> name = Handle<String>::cast(converted);
3653
3654 if (name->AsArrayIndex(&index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003655 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003656 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003657 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003658 }
3659}
3660
3661
lrn@chromium.org303ada72010-10-27 09:33:13 +00003662MaybeObject* Runtime::ForceSetObjectProperty(Handle<JSObject> js_object,
3663 Handle<Object> key,
3664 Handle<Object> value,
3665 PropertyAttributes attr) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003666 HandleScope scope;
3667
3668 // Check if the given key is an array index.
3669 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003670 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003671 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3672 // of a string using [] notation. We need to support this too in
3673 // JavaScript.
3674 // In the case of a String object we just need to redirect the assignment to
3675 // the underlying string if the index is in range. Since the underlying
3676 // string does nothing with the assignment then we can ignore such
3677 // assignments.
3678 if (js_object->IsStringObjectWithCharacterAt(index)) {
3679 return *value;
3680 }
3681
3682 return js_object->SetElement(index, *value);
3683 }
3684
3685 if (key->IsString()) {
3686 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003687 return js_object->SetElement(index, *value);
3688 } else {
3689 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003690 key_string->TryFlatten();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003691 return js_object->IgnoreAttributesAndSetLocalProperty(*key_string,
3692 *value,
3693 attr);
3694 }
3695 }
3696
3697 // Call-back into JavaScript to convert the key to a string.
3698 bool has_pending_exception = false;
3699 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3700 if (has_pending_exception) return Failure::Exception();
3701 Handle<String> name = Handle<String>::cast(converted);
3702
3703 if (name->AsArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003704 return js_object->SetElement(index, *value);
3705 } else {
3706 return js_object->IgnoreAttributesAndSetLocalProperty(*name, *value, attr);
3707 }
3708}
3709
3710
lrn@chromium.org303ada72010-10-27 09:33:13 +00003711MaybeObject* Runtime::ForceDeleteObjectProperty(Handle<JSObject> js_object,
3712 Handle<Object> key) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003713 HandleScope scope;
3714
3715 // Check if the given key is an array index.
3716 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003717 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003718 // In Firefox/SpiderMonkey, Safari and Opera you can access the
3719 // characters of a string using [] notation. In the case of a
3720 // String object we just need to redirect the deletion to the
3721 // underlying string if the index is in range. Since the
3722 // underlying string does nothing with the deletion, we can ignore
3723 // such deletions.
3724 if (js_object->IsStringObjectWithCharacterAt(index)) {
3725 return Heap::true_value();
3726 }
3727
3728 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
3729 }
3730
3731 Handle<String> key_string;
3732 if (key->IsString()) {
3733 key_string = Handle<String>::cast(key);
3734 } else {
3735 // Call-back into JavaScript to convert the key to a string.
3736 bool has_pending_exception = false;
3737 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3738 if (has_pending_exception) return Failure::Exception();
3739 key_string = Handle<String>::cast(converted);
3740 }
3741
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003742 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003743 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
3744}
3745
3746
lrn@chromium.org303ada72010-10-27 09:33:13 +00003747static MaybeObject* Runtime_SetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003748 NoHandleAllocation ha;
3749 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
3750
3751 Handle<Object> object = args.at<Object>(0);
3752 Handle<Object> key = args.at<Object>(1);
3753 Handle<Object> value = args.at<Object>(2);
3754
3755 // Compute attributes.
3756 PropertyAttributes attributes = NONE;
3757 if (args.length() == 4) {
3758 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003759 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003760 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003761 RUNTIME_ASSERT(
3762 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3763 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003764 }
3765 return Runtime::SetObjectProperty(object, key, value, attributes);
3766}
3767
3768
3769// Set a local property, even if it is READ_ONLY. If the property does not
3770// exist, it will be added with attributes NONE.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003771static MaybeObject* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003772 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003773 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003774 CONVERT_CHECKED(JSObject, object, args[0]);
3775 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003776 // Compute attributes.
3777 PropertyAttributes attributes = NONE;
3778 if (args.length() == 4) {
3779 CONVERT_CHECKED(Smi, value_obj, args[3]);
3780 int unchecked_value = value_obj->value();
3781 // Only attribute bits should be set.
3782 RUNTIME_ASSERT(
3783 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3784 attributes = static_cast<PropertyAttributes>(unchecked_value);
3785 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003786
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003787 return object->
3788 IgnoreAttributesAndSetLocalProperty(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003789}
3790
3791
lrn@chromium.org303ada72010-10-27 09:33:13 +00003792static MaybeObject* Runtime_DeleteProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003793 NoHandleAllocation ha;
3794 ASSERT(args.length() == 2);
3795
3796 CONVERT_CHECKED(JSObject, object, args[0]);
3797 CONVERT_CHECKED(String, key, args[1]);
ager@chromium.orge2902be2009-06-08 12:21:35 +00003798 return object->DeleteProperty(key, JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003799}
3800
3801
ager@chromium.org9085a012009-05-11 19:22:57 +00003802static Object* HasLocalPropertyImplementation(Handle<JSObject> object,
3803 Handle<String> key) {
3804 if (object->HasLocalProperty(*key)) return Heap::true_value();
3805 // Handle hidden prototypes. If there's a hidden prototype above this thing
3806 // then we have to check it for properties, because they are supposed to
3807 // look like they are on this object.
3808 Handle<Object> proto(object->GetPrototype());
3809 if (proto->IsJSObject() &&
3810 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
3811 return HasLocalPropertyImplementation(Handle<JSObject>::cast(proto), key);
3812 }
3813 return Heap::false_value();
3814}
3815
3816
lrn@chromium.org303ada72010-10-27 09:33:13 +00003817static MaybeObject* Runtime_HasLocalProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003818 NoHandleAllocation ha;
3819 ASSERT(args.length() == 2);
3820 CONVERT_CHECKED(String, key, args[1]);
3821
ager@chromium.org9085a012009-05-11 19:22:57 +00003822 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003823 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00003824 if (obj->IsJSObject()) {
3825 JSObject* object = JSObject::cast(obj);
3826 // Fast case - no interceptors.
3827 if (object->HasRealNamedProperty(key)) return Heap::true_value();
3828 // Slow case. Either it's not there or we have an interceptor. We should
3829 // have handles for this kind of deal.
3830 HandleScope scope;
3831 return HasLocalPropertyImplementation(Handle<JSObject>(object),
3832 Handle<String>(key));
3833 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003834 // Well, there is one exception: Handle [] on strings.
3835 uint32_t index;
3836 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00003837 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003838 if (index < static_cast<uint32_t>(string->length()))
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003839 return Heap::true_value();
3840 }
3841 }
3842 return Heap::false_value();
3843}
3844
3845
lrn@chromium.org303ada72010-10-27 09:33:13 +00003846static MaybeObject* Runtime_HasProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003847 NoHandleAllocation na;
3848 ASSERT(args.length() == 2);
3849
3850 // Only JS objects can have properties.
3851 if (args[0]->IsJSObject()) {
3852 JSObject* object = JSObject::cast(args[0]);
3853 CONVERT_CHECKED(String, key, args[1]);
3854 if (object->HasProperty(key)) return Heap::true_value();
3855 }
3856 return Heap::false_value();
3857}
3858
3859
lrn@chromium.org303ada72010-10-27 09:33:13 +00003860static MaybeObject* Runtime_HasElement(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003861 NoHandleAllocation na;
3862 ASSERT(args.length() == 2);
3863
3864 // Only JS objects can have elements.
3865 if (args[0]->IsJSObject()) {
3866 JSObject* object = JSObject::cast(args[0]);
3867 CONVERT_CHECKED(Smi, index_obj, args[1]);
3868 uint32_t index = index_obj->value();
3869 if (object->HasElement(index)) return Heap::true_value();
3870 }
3871 return Heap::false_value();
3872}
3873
3874
lrn@chromium.org303ada72010-10-27 09:33:13 +00003875static MaybeObject* Runtime_IsPropertyEnumerable(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003876 NoHandleAllocation ha;
3877 ASSERT(args.length() == 2);
3878
3879 CONVERT_CHECKED(JSObject, object, args[0]);
3880 CONVERT_CHECKED(String, key, args[1]);
3881
3882 uint32_t index;
3883 if (key->AsArrayIndex(&index)) {
3884 return Heap::ToBoolean(object->HasElement(index));
3885 }
3886
ager@chromium.org870a0b62008-11-04 11:43:05 +00003887 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
3888 return Heap::ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003889}
3890
3891
lrn@chromium.org303ada72010-10-27 09:33:13 +00003892static MaybeObject* Runtime_GetPropertyNames(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003893 HandleScope scope;
3894 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003895 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003896 return *GetKeysFor(object);
3897}
3898
3899
3900// Returns either a FixedArray as Runtime_GetPropertyNames,
3901// or, if the given object has an enum cache that contains
3902// all enumerable properties of the object and its prototypes
3903// have none, the map of the object. This is used to speed up
3904// the check for deletions during a for-in.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003905static MaybeObject* Runtime_GetPropertyNamesFast(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003906 ASSERT(args.length() == 1);
3907
3908 CONVERT_CHECKED(JSObject, raw_object, args[0]);
3909
3910 if (raw_object->IsSimpleEnum()) return raw_object->map();
3911
3912 HandleScope scope;
3913 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00003914 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
3915 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003916
3917 // Test again, since cache may have been built by preceding call.
3918 if (object->IsSimpleEnum()) return object->map();
3919
3920 return *content;
3921}
3922
3923
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003924// Find the length of the prototype chain that is to to handled as one. If a
3925// prototype object is hidden it is to be viewed as part of the the object it
3926// is prototype for.
3927static int LocalPrototypeChainLength(JSObject* obj) {
3928 int count = 1;
3929 Object* proto = obj->GetPrototype();
3930 while (proto->IsJSObject() &&
3931 JSObject::cast(proto)->map()->is_hidden_prototype()) {
3932 count++;
3933 proto = JSObject::cast(proto)->GetPrototype();
3934 }
3935 return count;
3936}
3937
3938
3939// Return the names of the local named properties.
3940// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00003941static MaybeObject* Runtime_GetLocalPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003942 HandleScope scope;
3943 ASSERT(args.length() == 1);
3944 if (!args[0]->IsJSObject()) {
3945 return Heap::undefined_value();
3946 }
3947 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3948
3949 // Skip the global proxy as it has no properties and always delegates to the
3950 // real global object.
3951 if (obj->IsJSGlobalProxy()) {
3952 // Only collect names if access is permitted.
3953 if (obj->IsAccessCheckNeeded() &&
3954 !Top::MayNamedAccess(*obj, Heap::undefined_value(), v8::ACCESS_KEYS)) {
3955 Top::ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
3956 return *Factory::NewJSArray(0);
3957 }
3958 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
3959 }
3960
3961 // Find the number of objects making up this.
3962 int length = LocalPrototypeChainLength(*obj);
3963
3964 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00003965 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003966 int total_property_count = 0;
3967 Handle<JSObject> jsproto = obj;
3968 for (int i = 0; i < length; i++) {
3969 // Only collect names if access is permitted.
3970 if (jsproto->IsAccessCheckNeeded() &&
3971 !Top::MayNamedAccess(*jsproto,
3972 Heap::undefined_value(),
3973 v8::ACCESS_KEYS)) {
3974 Top::ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
3975 return *Factory::NewJSArray(0);
3976 }
3977 int n;
3978 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
3979 local_property_count[i] = n;
3980 total_property_count += n;
3981 if (i < length - 1) {
3982 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
3983 }
3984 }
3985
3986 // Allocate an array with storage for all the property names.
3987 Handle<FixedArray> names = Factory::NewFixedArray(total_property_count);
3988
3989 // Get the property names.
3990 jsproto = obj;
3991 int proto_with_hidden_properties = 0;
3992 for (int i = 0; i < length; i++) {
3993 jsproto->GetLocalPropertyNames(*names,
3994 i == 0 ? 0 : local_property_count[i - 1]);
3995 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
3996 proto_with_hidden_properties++;
3997 }
3998 if (i < length - 1) {
3999 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4000 }
4001 }
4002
4003 // Filter out name of hidden propeties object.
4004 if (proto_with_hidden_properties > 0) {
4005 Handle<FixedArray> old_names = names;
4006 names = Factory::NewFixedArray(
4007 names->length() - proto_with_hidden_properties);
4008 int dest_pos = 0;
4009 for (int i = 0; i < total_property_count; i++) {
4010 Object* name = old_names->get(i);
4011 if (name == Heap::hidden_symbol()) {
4012 continue;
4013 }
4014 names->set(dest_pos++, name);
4015 }
4016 }
4017
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004018 return *Factory::NewJSArrayWithElements(names);
4019}
4020
4021
4022// Return the names of the local indexed properties.
4023// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004024static MaybeObject* Runtime_GetLocalElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004025 HandleScope scope;
4026 ASSERT(args.length() == 1);
4027 if (!args[0]->IsJSObject()) {
4028 return Heap::undefined_value();
4029 }
4030 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4031
4032 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4033 Handle<FixedArray> names = Factory::NewFixedArray(n);
4034 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4035 return *Factory::NewJSArrayWithElements(names);
4036}
4037
4038
4039// Return information on whether an object has a named or indexed interceptor.
4040// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004041static MaybeObject* Runtime_GetInterceptorInfo(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004042 HandleScope scope;
4043 ASSERT(args.length() == 1);
4044 if (!args[0]->IsJSObject()) {
4045 return Smi::FromInt(0);
4046 }
4047 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4048
4049 int result = 0;
4050 if (obj->HasNamedInterceptor()) result |= 2;
4051 if (obj->HasIndexedInterceptor()) result |= 1;
4052
4053 return Smi::FromInt(result);
4054}
4055
4056
4057// Return property names from named interceptor.
4058// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004059static MaybeObject* Runtime_GetNamedInterceptorPropertyNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004060 HandleScope scope;
4061 ASSERT(args.length() == 1);
4062 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4063
4064 if (obj->HasNamedInterceptor()) {
4065 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4066 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4067 }
4068 return Heap::undefined_value();
4069}
4070
4071
4072// Return element names from indexed interceptor.
4073// args[0]: object
lrn@chromium.org303ada72010-10-27 09:33:13 +00004074static MaybeObject* Runtime_GetIndexedInterceptorElementNames(Arguments args) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004075 HandleScope scope;
4076 ASSERT(args.length() == 1);
4077 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4078
4079 if (obj->HasIndexedInterceptor()) {
4080 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4081 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4082 }
4083 return Heap::undefined_value();
4084}
4085
4086
lrn@chromium.org303ada72010-10-27 09:33:13 +00004087static MaybeObject* Runtime_LocalKeys(Arguments args) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004088 ASSERT_EQ(args.length(), 1);
4089 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4090 HandleScope scope;
4091 Handle<JSObject> object(raw_object);
4092 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4093 LOCAL_ONLY);
4094 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4095 // property array and since the result is mutable we have to create
4096 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004097 int length = contents->length();
4098 Handle<FixedArray> copy = Factory::NewFixedArray(length);
4099 for (int i = 0; i < length; i++) {
4100 Object* entry = contents->get(i);
4101 if (entry->IsString()) {
4102 copy->set(i, entry);
4103 } else {
4104 ASSERT(entry->IsNumber());
4105 HandleScope scope;
4106 Handle<Object> entry_handle(entry);
4107 Handle<Object> entry_str = Factory::NumberToString(entry_handle);
4108 copy->set(i, *entry_str);
4109 }
4110 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004111 return *Factory::NewJSArrayWithElements(copy);
4112}
4113
4114
lrn@chromium.org303ada72010-10-27 09:33:13 +00004115static MaybeObject* Runtime_GetArgumentsProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004116 NoHandleAllocation ha;
4117 ASSERT(args.length() == 1);
4118
4119 // Compute the frame holding the arguments.
4120 JavaScriptFrameIterator it;
4121 it.AdvanceToArgumentsFrame();
4122 JavaScriptFrame* frame = it.frame();
4123
4124 // Get the actual number of provided arguments.
4125 const uint32_t n = frame->GetProvidedParametersCount();
4126
4127 // Try to convert the key to an index. If successful and within
4128 // index return the the argument from the frame.
4129 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004130 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004131 return frame->GetParameter(index);
4132 }
4133
4134 // Convert the key to a string.
4135 HandleScope scope;
4136 bool exception = false;
4137 Handle<Object> converted =
4138 Execution::ToString(args.at<Object>(0), &exception);
4139 if (exception) return Failure::Exception();
4140 Handle<String> key = Handle<String>::cast(converted);
4141
4142 // Try to convert the string key into an array index.
4143 if (key->AsArrayIndex(&index)) {
4144 if (index < n) {
4145 return frame->GetParameter(index);
4146 } else {
4147 return Top::initial_object_prototype()->GetElement(index);
4148 }
4149 }
4150
4151 // Handle special arguments properties.
4152 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
4153 if (key->Equals(Heap::callee_symbol())) return frame->function();
4154
4155 // Lookup in the initial Object.prototype object.
4156 return Top::initial_object_prototype()->GetProperty(*key);
4157}
4158
4159
lrn@chromium.org303ada72010-10-27 09:33:13 +00004160static MaybeObject* Runtime_ToFastProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004161 HandleScope scope;
4162
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004163 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004164 Handle<Object> object = args.at<Object>(0);
4165 if (object->IsJSObject()) {
4166 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004167 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004168 MaybeObject* ok = js_object->TransformToFastProperties(0);
4169 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004170 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004171 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004172 return *object;
4173}
4174
4175
lrn@chromium.org303ada72010-10-27 09:33:13 +00004176static MaybeObject* Runtime_ToSlowProperties(Arguments args) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004177 HandleScope scope;
4178
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004179 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004180 Handle<Object> object = args.at<Object>(0);
4181 if (object->IsJSObject()) {
4182 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004183 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004184 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004185 return *object;
4186}
4187
4188
lrn@chromium.org303ada72010-10-27 09:33:13 +00004189static MaybeObject* Runtime_ToBool(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190 NoHandleAllocation ha;
4191 ASSERT(args.length() == 1);
4192
4193 return args[0]->ToBoolean();
4194}
4195
4196
4197// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4198// Possible optimizations: put the type string into the oddballs.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004199static MaybeObject* Runtime_Typeof(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004200 NoHandleAllocation ha;
4201
4202 Object* obj = args[0];
4203 if (obj->IsNumber()) return Heap::number_symbol();
4204 HeapObject* heap_obj = HeapObject::cast(obj);
4205
4206 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004207 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004208
4209 InstanceType instance_type = heap_obj->map()->instance_type();
4210 if (instance_type < FIRST_NONSTRING_TYPE) {
4211 return Heap::string_symbol();
4212 }
4213
4214 switch (instance_type) {
4215 case ODDBALL_TYPE:
4216 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
4217 return Heap::boolean_symbol();
4218 }
4219 if (heap_obj->IsNull()) {
4220 return Heap::object_symbol();
4221 }
4222 ASSERT(heap_obj->IsUndefined());
4223 return Heap::undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004224 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004225 return Heap::function_symbol();
4226 default:
4227 // For any kind of object not handled above, the spec rule for
4228 // host objects gives that it is okay to return "object"
4229 return Heap::object_symbol();
4230 }
4231}
4232
4233
lrn@chromium.org25156de2010-04-06 13:10:27 +00004234static bool AreDigits(const char*s, int from, int to) {
4235 for (int i = from; i < to; i++) {
4236 if (s[i] < '0' || s[i] > '9') return false;
4237 }
4238
4239 return true;
4240}
4241
4242
4243static int ParseDecimalInteger(const char*s, int from, int to) {
4244 ASSERT(to - from < 10); // Overflow is not possible.
4245 ASSERT(from < to);
4246 int d = s[from] - '0';
4247
4248 for (int i = from + 1; i < to; i++) {
4249 d = 10 * d + (s[i] - '0');
4250 }
4251
4252 return d;
4253}
4254
4255
lrn@chromium.org303ada72010-10-27 09:33:13 +00004256static MaybeObject* Runtime_StringToNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004257 NoHandleAllocation ha;
4258 ASSERT(args.length() == 1);
4259 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004260 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004261
4262 // Fast case: short integer or some sorts of junk values.
4263 int len = subject->length();
4264 if (subject->IsSeqAsciiString()) {
4265 if (len == 0) return Smi::FromInt(0);
4266
4267 char const* data = SeqAsciiString::cast(subject)->GetChars();
4268 bool minus = (data[0] == '-');
4269 int start_pos = (minus ? 1 : 0);
4270
4271 if (start_pos == len) {
4272 return Heap::nan_value();
4273 } else if (data[start_pos] > '9') {
4274 // Fast check for a junk value. A valid string may start from a
4275 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4276 // the 'I' character ('Infinity'). All of that have codes not greater than
4277 // '9' except 'I'.
4278 if (data[start_pos] != 'I') {
4279 return Heap::nan_value();
4280 }
4281 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4282 // The maximal/minimal smi has 10 digits. If the string has less digits we
4283 // know it will fit into the smi-data type.
4284 int d = ParseDecimalInteger(data, start_pos, len);
4285 if (minus) {
4286 if (d == 0) return Heap::minus_zero_value();
4287 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004288 } else if (!subject->HasHashCode() &&
4289 len <= String::kMaxArrayIndexSize &&
4290 (len == 1 || data[0] != '0')) {
4291 // String hash is not calculated yet but all the data are present.
4292 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004293 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004294#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004295 subject->Hash(); // Force hash calculation.
4296 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4297 static_cast<int>(hash));
4298#endif
4299 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004300 }
4301 return Smi::FromInt(d);
4302 }
4303 }
4304
4305 // Slower case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004306 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
4307}
4308
4309
lrn@chromium.org303ada72010-10-27 09:33:13 +00004310static MaybeObject* Runtime_StringFromCharCodeArray(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004311 NoHandleAllocation ha;
4312 ASSERT(args.length() == 1);
4313
4314 CONVERT_CHECKED(JSArray, codes, args[0]);
4315 int length = Smi::cast(codes->length())->value();
4316
4317 // Check if the string can be ASCII.
4318 int i;
4319 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004320 Object* element;
4321 { MaybeObject* maybe_element = codes->GetElement(i);
4322 // We probably can't get an exception here, but just in order to enforce
4323 // the checking of inputs in the runtime calls we check here.
4324 if (!maybe_element->ToObject(&element)) return maybe_element;
4325 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004326 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4327 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4328 break;
4329 }
4330
lrn@chromium.org303ada72010-10-27 09:33:13 +00004331 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004332 if (i == length) { // The string is ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004333 maybe_object = Heap::AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004334 } else { // The string is not ASCII.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004335 maybe_object = Heap::AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004336 }
4337
lrn@chromium.org303ada72010-10-27 09:33:13 +00004338 Object* object = NULL;
4339 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004340 String* result = String::cast(object);
4341 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004342 Object* element;
4343 { MaybeObject* maybe_element = codes->GetElement(i);
4344 if (!maybe_element->ToObject(&element)) return maybe_element;
4345 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004346 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004347 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004348 }
4349 return result;
4350}
4351
4352
4353// kNotEscaped is generated by the following:
4354//
4355// #!/bin/perl
4356// for (my $i = 0; $i < 256; $i++) {
4357// print "\n" if $i % 16 == 0;
4358// my $c = chr($i);
4359// my $escaped = 1;
4360// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4361// print $escaped ? "0, " : "1, ";
4362// }
4363
4364
4365static bool IsNotEscaped(uint16_t character) {
4366 // Only for 8 bit characters, the rest are always escaped (in a different way)
4367 ASSERT(character < 256);
4368 static const char kNotEscaped[256] = {
4369 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 1, 1, 0, 1, 1, 1,
4372 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4373 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4374 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4375 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4376 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4377 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4378 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4379 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4380 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4381 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4382 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4383 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4384 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4385 };
4386 return kNotEscaped[character] != 0;
4387}
4388
4389
lrn@chromium.org303ada72010-10-27 09:33:13 +00004390static MaybeObject* Runtime_URIEscape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004391 const char hex_chars[] = "0123456789ABCDEF";
4392 NoHandleAllocation ha;
4393 ASSERT(args.length() == 1);
4394 CONVERT_CHECKED(String, source, args[0]);
4395
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004396 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004397
4398 int escaped_length = 0;
4399 int length = source->length();
4400 {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004401 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004402 buffer->Reset(source);
4403 while (buffer->has_more()) {
4404 uint16_t character = buffer->GetNext();
4405 if (character >= 256) {
4406 escaped_length += 6;
4407 } else if (IsNotEscaped(character)) {
4408 escaped_length++;
4409 } else {
4410 escaped_length += 3;
4411 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004412 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004413 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004414 if (escaped_length > String::kMaxLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004415 Top::context()->mark_out_of_memory();
4416 return Failure::OutOfMemoryException();
4417 }
4418 }
4419 }
4420 // No length change implies no change. Return original string if no change.
4421 if (escaped_length == length) {
4422 return source;
4423 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004424 Object* o;
4425 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(escaped_length);
4426 if (!maybe_o->ToObject(&o)) return maybe_o;
4427 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004428 String* destination = String::cast(o);
4429 int dest_position = 0;
4430
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004431 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004432 buffer->Rewind();
4433 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004434 uint16_t chr = buffer->GetNext();
4435 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004436 destination->Set(dest_position, '%');
4437 destination->Set(dest_position+1, 'u');
4438 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4439 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4440 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4441 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004442 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004443 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004444 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004445 dest_position++;
4446 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004447 destination->Set(dest_position, '%');
4448 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4449 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004450 dest_position += 3;
4451 }
4452 }
4453 return destination;
4454}
4455
4456
4457static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4458 static const signed char kHexValue['g'] = {
4459 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4460 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4461 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4462 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4463 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4464 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4465 -1, 10, 11, 12, 13, 14, 15 };
4466
4467 if (character1 > 'f') return -1;
4468 int hi = kHexValue[character1];
4469 if (hi == -1) return -1;
4470 if (character2 > 'f') return -1;
4471 int lo = kHexValue[character2];
4472 if (lo == -1) return -1;
4473 return (hi << 4) + lo;
4474}
4475
4476
ager@chromium.org870a0b62008-11-04 11:43:05 +00004477static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004478 int i,
4479 int length,
4480 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004481 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004482 int32_t hi = 0;
4483 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004484 if (character == '%' &&
4485 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004486 source->Get(i + 1) == 'u' &&
4487 (hi = TwoDigitHex(source->Get(i + 2),
4488 source->Get(i + 3))) != -1 &&
4489 (lo = TwoDigitHex(source->Get(i + 4),
4490 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004491 *step = 6;
4492 return (hi << 8) + lo;
4493 } else if (character == '%' &&
4494 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004495 (lo = TwoDigitHex(source->Get(i + 1),
4496 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004497 *step = 3;
4498 return lo;
4499 } else {
4500 *step = 1;
4501 return character;
4502 }
4503}
4504
4505
lrn@chromium.org303ada72010-10-27 09:33:13 +00004506static MaybeObject* Runtime_URIUnescape(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004507 NoHandleAllocation ha;
4508 ASSERT(args.length() == 1);
4509 CONVERT_CHECKED(String, source, args[0]);
4510
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004511 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004512
4513 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004514 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004515
4516 int unescaped_length = 0;
4517 for (int i = 0; i < length; unescaped_length++) {
4518 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004519 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004520 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004521 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004522 i += step;
4523 }
4524
4525 // No length change implies no change. Return original string if no change.
4526 if (unescaped_length == length)
4527 return source;
4528
lrn@chromium.org303ada72010-10-27 09:33:13 +00004529 Object* o;
4530 { MaybeObject* maybe_o = ascii ?
4531 Heap::AllocateRawAsciiString(unescaped_length) :
4532 Heap::AllocateRawTwoByteString(unescaped_length);
4533 if (!maybe_o->ToObject(&o)) return maybe_o;
4534 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004535 String* destination = String::cast(o);
4536
4537 int dest_position = 0;
4538 for (int i = 0; i < length; dest_position++) {
4539 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004540 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004541 i += step;
4542 }
4543 return destination;
4544}
4545
4546
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004547static const unsigned int kQuoteTableLength = 128u;
4548
4549static const char* const JsonQuotes[kQuoteTableLength] = {
4550 "\\u0000", "\\u0001", "\\u0002", "\\u0003",
4551 "\\u0004", "\\u0005", "\\u0006", "\\u0007",
4552 "\\b", "\\t", "\\n", "\\u000b",
4553 "\\f", "\\r", "\\u000e", "\\u000f",
4554 "\\u0010", "\\u0011", "\\u0012", "\\u0013",
4555 "\\u0014", "\\u0015", "\\u0016", "\\u0017",
4556 "\\u0018", "\\u0019", "\\u001a", "\\u001b",
4557 "\\u001c", "\\u001d", "\\u001e", "\\u001f",
4558 NULL, NULL, "\\\"", NULL,
4559 NULL, NULL, NULL, NULL,
4560 NULL, NULL, NULL, NULL,
4561 NULL, NULL, NULL, NULL,
4562 NULL, NULL, NULL, NULL,
4563 NULL, NULL, NULL, NULL,
4564 NULL, NULL, NULL, NULL,
4565 NULL, NULL, NULL, NULL,
4566 NULL, NULL, NULL, NULL,
4567 NULL, NULL, NULL, NULL,
4568 NULL, NULL, NULL, NULL,
4569 NULL, NULL, NULL, NULL,
4570 NULL, NULL, NULL, NULL,
4571 NULL, NULL, NULL, NULL,
4572 NULL, NULL, NULL, NULL,
4573 "\\\\", NULL, NULL, NULL,
4574 NULL, NULL, NULL, NULL,
4575 NULL, NULL, NULL, NULL,
4576 NULL, NULL, NULL, NULL,
4577 NULL, NULL, NULL, NULL,
4578 NULL, NULL, NULL, NULL,
4579 NULL, NULL, NULL, NULL,
4580 NULL, NULL, NULL, NULL,
4581 NULL, NULL, NULL, NULL,
4582};
4583
4584
4585static const byte JsonQuoteLengths[kQuoteTableLength] = {
4586 6, 6, 6, 6, 6, 6, 6, 6,
4587 2, 2, 2, 6, 2, 2, 6, 6,
4588 6, 6, 6, 6, 6, 6, 6, 6,
4589 6, 6, 6, 6, 6, 6, 6, 6,
4590 1, 1, 2, 1, 1, 1, 1, 1,
4591 1, 1, 1, 1, 1, 1, 1, 1,
4592 1, 1, 1, 1, 1, 1, 1, 1,
4593 1, 1, 1, 1, 1, 1, 1, 1,
4594 1, 1, 1, 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, 2, 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, 1, 1, 1, 1,
4602};
4603
4604
4605template <typename Char>
4606Char* WriteString(Char* dst, const char* src_string) {
4607 char c;
4608 for (c = *src_string; c; c = *src_string) {
4609 *dst = c;
4610 dst++;
4611 src_string++;
4612 }
4613 return dst;
4614}
4615
4616
4617template <typename StringType>
4618MaybeObject* AllocateRawString(int length);
4619
4620
4621template <>
4622MaybeObject* AllocateRawString<SeqTwoByteString>(int length) {
4623 return Heap::AllocateRawTwoByteString(length);
4624}
4625
4626
4627template <>
4628MaybeObject* AllocateRawString<SeqAsciiString>(int length) {
4629 return Heap::AllocateRawAsciiString(length);
4630}
4631
4632
4633template <typename Char, typename StringType>
4634static MaybeObject* QuoteJsonString(Vector<const Char> characters) {
4635 int length = characters.length();
4636 int quoted_length = 0;
4637 for (int i = 0; i < length; i++) {
4638 unsigned int c = characters[i];
4639 if (sizeof(Char) > 1u) {
4640 quoted_length += (c >= kQuoteTableLength) ? 1 : JsonQuoteLengths[c];
4641 } else {
4642 quoted_length += JsonQuoteLengths[c];
4643 }
4644 }
4645 Counters::quote_json_char_count.Increment(length);
4646
4647 // Add space for quotes.
4648 quoted_length += 2;
4649
4650 MaybeObject* new_alloc = AllocateRawString<StringType>(quoted_length);
4651 Object* new_object;
4652 if (!new_alloc->ToObject(&new_object)) {
4653 Counters::quote_json_char_recount.Increment(length);
4654 return new_alloc;
4655 }
4656 StringType* new_string = StringType::cast(new_object);
4657
4658
4659 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
4660 Char* write_cursor = reinterpret_cast<Char*>(
4661 new_string->address() + SeqAsciiString::kHeaderSize);
4662 *(write_cursor++) = '"';
4663 const Char* read_cursor = characters.start();
4664 if (quoted_length == length + 2) {
4665 CopyChars(write_cursor, read_cursor, length);
4666 write_cursor += length;
4667 } else {
4668 const Char* end = read_cursor + length;
4669 while (read_cursor < end) {
4670 Char c = *(read_cursor++);
4671 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
4672 *(write_cursor++) = c;
4673 } else {
4674 const char* replacement = JsonQuotes[static_cast<unsigned>(c)];
4675 if (!replacement) {
4676 *(write_cursor++) = c;
4677 } else {
4678 write_cursor = WriteString(write_cursor, replacement);
4679 }
4680 }
4681 }
4682 }
4683 *(write_cursor++) = '"';
4684 ASSERT_EQ(SeqAsciiString::kHeaderSize + quoted_length * sizeof(Char),
4685 reinterpret_cast<Address>(write_cursor) - new_string->address());
4686 return new_string;
4687}
4688
4689
4690static MaybeObject* Runtime_QuoteJSONString(Arguments args) {
4691 NoHandleAllocation ha;
4692 CONVERT_CHECKED(String, str, args[0]);
4693 if (!str->IsFlat()) {
4694 MaybeObject* try_flatten = str->TryFlatten();
4695 Object* flat;
4696 if (!try_flatten->ToObject(&flat)) {
4697 return try_flatten;
4698 }
4699 str = String::cast(flat);
4700 ASSERT(str->IsFlat());
4701 }
4702 if (str->IsTwoByteRepresentation()) {
4703 return QuoteJsonString<uc16, SeqTwoByteString>(str->ToUC16Vector());
4704 } else {
4705 return QuoteJsonString<char, SeqAsciiString>(str->ToAsciiVector());
4706 }
4707}
4708
4709
4710
lrn@chromium.org303ada72010-10-27 09:33:13 +00004711static MaybeObject* Runtime_StringParseInt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004712 NoHandleAllocation ha;
4713
4714 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004715 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004716
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004717 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004718
lrn@chromium.org25156de2010-04-06 13:10:27 +00004719 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
4720 double value = StringToInt(s, radix);
4721 return Heap::NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004722}
4723
4724
lrn@chromium.org303ada72010-10-27 09:33:13 +00004725static MaybeObject* Runtime_StringParseFloat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004726 NoHandleAllocation ha;
4727 CONVERT_CHECKED(String, str, args[0]);
4728
4729 // ECMA-262 section 15.1.2.3, empty string is NaN
4730 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
4731
4732 // Create a number object from the value.
4733 return Heap::NumberFromDouble(value);
4734}
4735
4736
4737static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
4738static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
4739
4740
4741template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00004742MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
4743 String* s,
4744 int length,
4745 int input_string_length,
4746 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004747 // We try this twice, once with the assumption that the result is no longer
4748 // than the input and, if that assumption breaks, again with the exact
4749 // length. This may not be pretty, but it is nicer than what was here before
4750 // and I hereby claim my vaffel-is.
4751 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004752 // Allocate the resulting string.
4753 //
4754 // NOTE: This assumes that the upper/lower case of an ascii
4755 // character is also ascii. This is currently the case, but it
4756 // might break in the future if we implement more context and locale
4757 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004758 Object* o;
4759 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
4760 ? Heap::AllocateRawAsciiString(length)
4761 : Heap::AllocateRawTwoByteString(length);
4762 if (!maybe_o->ToObject(&o)) return maybe_o;
4763 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004764 String* result = String::cast(o);
4765 bool has_changed_character = false;
4766
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004767 // Convert all characters to upper case, assuming that they will fit
4768 // in the buffer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004769 Access<StringInputBuffer> buffer(&runtime_string_input_buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004770 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00004771 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004772 // We can assume that the string is not empty
4773 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004774 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004775 bool has_next = buffer->has_more();
4776 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004777 int char_length = mapping->get(current, next, chars);
4778 if (char_length == 0) {
4779 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004780 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004781 i++;
4782 } else if (char_length == 1) {
4783 // Common case: converting the letter resulted in one character.
4784 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004785 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004786 has_changed_character = true;
4787 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004788 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004789 // We've assumed that the result would be as long as the
4790 // input but here is a character that converts to several
4791 // characters. No matter, we calculate the exact length
4792 // of the result and try the whole thing again.
4793 //
4794 // Note that this leaves room for optimization. We could just
4795 // memcpy what we already have to the result string. Also,
4796 // the result string is the last object allocated we could
4797 // "realloc" it and probably, in the vast majority of cases,
4798 // extend the existing string to be able to hold the full
4799 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004800 int next_length = 0;
4801 if (has_next) {
4802 next_length = mapping->get(next, 0, chars);
4803 if (next_length == 0) next_length = 1;
4804 }
4805 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004806 while (buffer->has_more()) {
4807 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004808 // NOTE: we use 0 as the next character here because, while
4809 // the next character may affect what a character converts to,
4810 // it does not in any case affect the length of what it convert
4811 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004812 int char_length = mapping->get(current, 0, chars);
4813 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00004814 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004815 if (current_length > Smi::kMaxValue) {
4816 Top::context()->mark_out_of_memory();
4817 return Failure::OutOfMemoryException();
4818 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004819 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004820 // Try again with the real length.
4821 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004822 } else {
4823 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004824 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004825 i++;
4826 }
4827 has_changed_character = true;
4828 }
4829 current = next;
4830 }
4831 if (has_changed_character) {
4832 return result;
4833 } else {
4834 // If we didn't actually change anything in doing the conversion
4835 // we simple return the result and let the converted string
4836 // become garbage; there is no reason to keep two identical strings
4837 // alive.
4838 return s;
4839 }
4840}
4841
4842
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004843namespace {
4844
lrn@chromium.org303ada72010-10-27 09:33:13 +00004845static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
4846
4847
4848// Given a word and two range boundaries returns a word with high bit
4849// set in every byte iff the corresponding input byte was strictly in
4850// the range (m, n). All the other bits in the result are cleared.
4851// This function is only useful when it can be inlined and the
4852// boundaries are statically known.
4853// Requires: all bytes in the input word and the boundaries must be
4854// ascii (less than 0x7F).
4855static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
4856 // Every byte in an ascii string is less than or equal to 0x7F.
4857 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
4858 // Use strict inequalities since in edge cases the function could be
4859 // further simplified.
4860 ASSERT(0 < m && m < n && n < 0x7F);
4861 // Has high bit set in every w byte less than n.
4862 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
4863 // Has high bit set in every w byte greater than m.
4864 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
4865 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
4866}
4867
4868
4869enum AsciiCaseConversion {
4870 ASCII_TO_LOWER,
4871 ASCII_TO_UPPER
4872};
4873
4874
4875template <AsciiCaseConversion dir>
4876struct FastAsciiConverter {
4877 static bool Convert(char* dst, char* src, int length) {
4878#ifdef DEBUG
4879 char* saved_dst = dst;
4880 char* saved_src = src;
4881#endif
4882 // We rely on the distance between upper and lower case letters
4883 // being a known power of 2.
4884 ASSERT('a' - 'A' == (1 << 5));
4885 // Boundaries for the range of input characters than require conversion.
4886 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
4887 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
4888 bool changed = false;
4889 char* const limit = src + length;
4890#ifdef V8_HOST_CAN_READ_UNALIGNED
4891 // Process the prefix of the input that requires no conversion one
4892 // (machine) word at a time.
4893 while (src <= limit - sizeof(uintptr_t)) {
4894 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
4895 if (AsciiRangeMask(w, lo, hi) != 0) {
4896 changed = true;
4897 break;
4898 }
4899 *reinterpret_cast<uintptr_t*>(dst) = w;
4900 src += sizeof(uintptr_t);
4901 dst += sizeof(uintptr_t);
4902 }
4903 // Process the remainder of the input performing conversion when
4904 // required one word at a time.
4905 while (src <= limit - sizeof(uintptr_t)) {
4906 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
4907 uintptr_t m = AsciiRangeMask(w, lo, hi);
4908 // The mask has high (7th) bit set in every byte that needs
4909 // conversion and we know that the distance between cases is
4910 // 1 << 5.
4911 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
4912 src += sizeof(uintptr_t);
4913 dst += sizeof(uintptr_t);
4914 }
4915#endif
4916 // Process the last few bytes of the input (or the whole input if
4917 // unaligned access is not supported).
4918 while (src < limit) {
4919 char c = *src;
4920 if (lo < c && c < hi) {
4921 c ^= (1 << 5);
4922 changed = true;
4923 }
4924 *dst = c;
4925 ++src;
4926 ++dst;
4927 }
4928#ifdef DEBUG
4929 CheckConvert(saved_dst, saved_src, length, changed);
4930#endif
4931 return changed;
4932 }
4933
4934#ifdef DEBUG
4935 static void CheckConvert(char* dst, char* src, int length, bool changed) {
4936 bool expected_changed = false;
4937 for (int i = 0; i < length; i++) {
4938 if (dst[i] == src[i]) continue;
4939 expected_changed = true;
4940 if (dir == ASCII_TO_LOWER) {
4941 ASSERT('A' <= src[i] && src[i] <= 'Z');
4942 ASSERT(dst[i] == src[i] + ('a' - 'A'));
4943 } else {
4944 ASSERT(dir == ASCII_TO_UPPER);
4945 ASSERT('a' <= src[i] && src[i] <= 'z');
4946 ASSERT(dst[i] == src[i] - ('a' - 'A'));
4947 }
4948 }
4949 ASSERT(expected_changed == changed);
4950 }
4951#endif
4952};
4953
4954
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004955struct ToLowerTraits {
4956 typedef unibrow::ToLowercase UnibrowConverter;
4957
lrn@chromium.org303ada72010-10-27 09:33:13 +00004958 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004959};
4960
4961
4962struct ToUpperTraits {
4963 typedef unibrow::ToUppercase UnibrowConverter;
4964
lrn@chromium.org303ada72010-10-27 09:33:13 +00004965 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004966};
4967
4968} // namespace
4969
4970
4971template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00004972MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004973 Arguments args,
4974 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004975 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004976 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00004977 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004978
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004979 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004980 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004981 if (length == 0) return s;
4982
4983 // Simpler handling of ascii strings.
4984 //
4985 // NOTE: This assumes that the upper/lower case of an ascii
4986 // character is also ascii. This is currently the case, but it
4987 // might break in the future if we implement more context and locale
4988 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00004989 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004990 Object* o;
4991 { MaybeObject* maybe_o = Heap::AllocateRawAsciiString(length);
4992 if (!maybe_o->ToObject(&o)) return maybe_o;
4993 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004994 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004995 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00004996 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004997 return has_changed_character ? result : s;
4998 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004999
lrn@chromium.org303ada72010-10-27 09:33:13 +00005000 Object* answer;
5001 { MaybeObject* maybe_answer = ConvertCaseHelper(s, length, length, mapping);
5002 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5003 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005004 if (answer->IsSmi()) {
5005 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005006 { MaybeObject* maybe_answer =
5007 ConvertCaseHelper(s, Smi::cast(answer)->value(), length, mapping);
5008 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5009 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005010 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005011 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005012}
5013
5014
lrn@chromium.org303ada72010-10-27 09:33:13 +00005015static MaybeObject* Runtime_StringToLowerCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005016 return ConvertCase<ToLowerTraits>(args, &to_lower_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005017}
5018
5019
lrn@chromium.org303ada72010-10-27 09:33:13 +00005020static MaybeObject* Runtime_StringToUpperCase(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005021 return ConvertCase<ToUpperTraits>(args, &to_upper_mapping);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005022}
5023
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005024
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005025static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5026 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5027}
5028
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005029
lrn@chromium.org303ada72010-10-27 09:33:13 +00005030static MaybeObject* Runtime_StringTrim(Arguments args) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005031 NoHandleAllocation ha;
5032 ASSERT(args.length() == 3);
5033
5034 CONVERT_CHECKED(String, s, args[0]);
5035 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5036 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5037
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005038 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005039 int length = s->length();
5040
5041 int left = 0;
5042 if (trimLeft) {
5043 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5044 left++;
5045 }
5046 }
5047
5048 int right = length;
5049 if (trimRight) {
5050 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5051 right--;
5052 }
5053 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005054 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005055}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005056
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005057
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005058template <typename SubjectChar, typename PatternChar>
5059void FindStringIndices(Vector<const SubjectChar> subject,
5060 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005061 ZoneList<int>* indices,
5062 unsigned int limit) {
5063 ASSERT(limit > 0);
5064 // Collect indices of pattern in subject, and the end-of-string index.
5065 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005066 StringSearch<PatternChar, SubjectChar> search(pattern);
5067 int pattern_length = pattern.length();
5068 int index = 0;
5069 while (limit > 0) {
5070 index = search.Search(subject, index);
5071 if (index < 0) return;
5072 indices->Add(index);
5073 index += pattern_length;
5074 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005075 }
5076}
5077
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005078
lrn@chromium.org303ada72010-10-27 09:33:13 +00005079static MaybeObject* Runtime_StringSplit(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005080 ASSERT(args.length() == 3);
5081 HandleScope handle_scope;
5082 CONVERT_ARG_CHECKED(String, subject, 0);
5083 CONVERT_ARG_CHECKED(String, pattern, 1);
5084 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5085
5086 int subject_length = subject->length();
5087 int pattern_length = pattern->length();
5088 RUNTIME_ASSERT(pattern_length > 0);
5089
5090 // The limit can be very large (0xffffffffu), but since the pattern
5091 // isn't empty, we can never create more parts than ~half the length
5092 // of the subject.
5093
5094 if (!subject->IsFlat()) FlattenString(subject);
5095
5096 static const int kMaxInitialListCapacity = 16;
5097
5098 ZoneScope scope(DELETE_ON_EXIT);
5099
5100 // Find (up to limit) indices of separator and end-of-string in subject
5101 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5102 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005103 if (!pattern->IsFlat()) FlattenString(pattern);
5104
5105 // No allocation block.
5106 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005107 AssertNoAllocation nogc;
5108 if (subject->IsAsciiRepresentation()) {
5109 Vector<const char> subject_vector = subject->ToAsciiVector();
5110 if (pattern->IsAsciiRepresentation()) {
5111 FindStringIndices(subject_vector,
5112 pattern->ToAsciiVector(),
5113 &indices,
5114 limit);
5115 } else {
5116 FindStringIndices(subject_vector,
5117 pattern->ToUC16Vector(),
5118 &indices,
5119 limit);
5120 }
5121 } else {
5122 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5123 if (pattern->IsAsciiRepresentation()) {
5124 FindStringIndices(subject_vector,
5125 pattern->ToAsciiVector(),
5126 &indices,
5127 limit);
5128 } else {
5129 FindStringIndices(subject_vector,
5130 pattern->ToUC16Vector(),
5131 &indices,
5132 limit);
5133 }
5134 }
5135 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005136
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005137 if (static_cast<uint32_t>(indices.length()) < limit) {
5138 indices.Add(subject_length);
5139 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005140
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005141 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005142
5143 // Create JSArray of substrings separated by separator.
5144 int part_count = indices.length();
5145
5146 Handle<JSArray> result = Factory::NewJSArray(part_count);
5147 result->set_length(Smi::FromInt(part_count));
5148
5149 ASSERT(result->HasFastElements());
5150
5151 if (part_count == 1 && indices.at(0) == subject_length) {
5152 FixedArray::cast(result->elements())->set(0, *subject);
5153 return *result;
5154 }
5155
5156 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5157 int part_start = 0;
5158 for (int i = 0; i < part_count; i++) {
5159 HandleScope local_loop_handle;
5160 int part_end = indices.at(i);
5161 Handle<String> substring =
5162 Factory::NewSubString(subject, part_start, part_end);
5163 elements->set(i, *substring);
5164 part_start = part_end + pattern_length;
5165 }
5166
5167 return *result;
5168}
5169
5170
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005171// Copies ascii characters to the given fixed array looking up
5172// one-char strings in the cache. Gives up on the first char that is
5173// not in the cache and fills the remainder with smi zeros. Returns
5174// the length of the successfully copied prefix.
5175static int CopyCachedAsciiCharsToArray(const char* chars,
5176 FixedArray* elements,
5177 int length) {
5178 AssertNoAllocation nogc;
5179 FixedArray* ascii_cache = Heap::single_character_string_cache();
5180 Object* undefined = Heap::undefined_value();
5181 int i;
5182 for (i = 0; i < length; ++i) {
5183 Object* value = ascii_cache->get(chars[i]);
5184 if (value == undefined) break;
5185 ASSERT(!Heap::InNewSpace(value));
5186 elements->set(i, value, SKIP_WRITE_BARRIER);
5187 }
5188 if (i < length) {
5189 ASSERT(Smi::FromInt(0) == 0);
5190 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5191 }
5192#ifdef DEBUG
5193 for (int j = 0; j < length; ++j) {
5194 Object* element = elements->get(j);
5195 ASSERT(element == Smi::FromInt(0) ||
5196 (element->IsString() && String::cast(element)->LooksValid()));
5197 }
5198#endif
5199 return i;
5200}
5201
5202
5203// Converts a String to JSArray.
5204// For example, "foo" => ["f", "o", "o"].
lrn@chromium.org303ada72010-10-27 09:33:13 +00005205static MaybeObject* Runtime_StringToArray(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005206 HandleScope scope;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005207 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005208 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005209 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005210
5211 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005212 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005213
5214 Handle<FixedArray> elements;
5215 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005216 Object* obj;
5217 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(length);
5218 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5219 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005220 elements = Handle<FixedArray>(FixedArray::cast(obj));
5221
5222 Vector<const char> chars = s->ToAsciiVector();
5223 // Note, this will initialize all elements (not only the prefix)
5224 // to prevent GC from seeing partially initialized array.
5225 int num_copied_from_cache = CopyCachedAsciiCharsToArray(chars.start(),
5226 *elements,
5227 length);
5228
5229 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005230 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5231 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005232 }
5233 } else {
5234 elements = Factory::NewFixedArray(length);
5235 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005236 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5237 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005238 }
5239 }
5240
5241#ifdef DEBUG
5242 for (int i = 0; i < length; ++i) {
5243 ASSERT(String::cast(elements->get(i))->length() == 1);
5244 }
5245#endif
5246
5247 return *Factory::NewJSArrayWithElements(elements);
5248}
5249
5250
lrn@chromium.org303ada72010-10-27 09:33:13 +00005251static MaybeObject* Runtime_NewStringWrapper(Arguments args) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005252 NoHandleAllocation ha;
5253 ASSERT(args.length() == 1);
5254 CONVERT_CHECKED(String, value, args[0]);
5255 return value->ToObject();
5256}
5257
5258
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005259bool Runtime::IsUpperCaseChar(uint16_t ch) {
5260 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
5261 int char_length = to_upper_mapping.get(ch, 0, chars);
5262 return char_length == 0;
5263}
5264
5265
lrn@chromium.org303ada72010-10-27 09:33:13 +00005266static MaybeObject* Runtime_NumberToString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005267 NoHandleAllocation ha;
5268 ASSERT(args.length() == 1);
5269
5270 Object* number = args[0];
5271 RUNTIME_ASSERT(number->IsNumber());
5272
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005273 return Heap::NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005274}
5275
5276
lrn@chromium.org303ada72010-10-27 09:33:13 +00005277static MaybeObject* Runtime_NumberToStringSkipCache(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005278 NoHandleAllocation ha;
5279 ASSERT(args.length() == 1);
5280
5281 Object* number = args[0];
5282 RUNTIME_ASSERT(number->IsNumber());
5283
5284 return Heap::NumberToString(number, false);
5285}
5286
5287
lrn@chromium.org303ada72010-10-27 09:33:13 +00005288static MaybeObject* Runtime_NumberToInteger(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005289 NoHandleAllocation ha;
5290 ASSERT(args.length() == 1);
5291
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005292 CONVERT_DOUBLE_CHECKED(number, args[0]);
5293
5294 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5295 if (number > 0 && number <= Smi::kMaxValue) {
5296 return Smi::FromInt(static_cast<int>(number));
5297 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005298 return Heap::NumberFromDouble(DoubleToInteger(number));
5299}
5300
5301
lrn@chromium.org303ada72010-10-27 09:33:13 +00005302static MaybeObject* Runtime_NumberToIntegerMapMinusZero(Arguments args) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005303 NoHandleAllocation ha;
5304 ASSERT(args.length() == 1);
5305
5306 CONVERT_DOUBLE_CHECKED(number, args[0]);
5307
5308 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5309 if (number > 0 && number <= Smi::kMaxValue) {
5310 return Smi::FromInt(static_cast<int>(number));
5311 }
5312
5313 double double_value = DoubleToInteger(number);
5314 // Map both -0 and +0 to +0.
5315 if (double_value == 0) double_value = 0;
5316
5317 return Heap::NumberFromDouble(double_value);
5318}
5319
5320
lrn@chromium.org303ada72010-10-27 09:33:13 +00005321static MaybeObject* Runtime_NumberToJSUint32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005322 NoHandleAllocation ha;
5323 ASSERT(args.length() == 1);
5324
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005325 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005326 return Heap::NumberFromUint32(number);
5327}
5328
5329
lrn@chromium.org303ada72010-10-27 09:33:13 +00005330static MaybeObject* Runtime_NumberToJSInt32(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005331 NoHandleAllocation ha;
5332 ASSERT(args.length() == 1);
5333
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005334 CONVERT_DOUBLE_CHECKED(number, args[0]);
5335
5336 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5337 if (number > 0 && number <= Smi::kMaxValue) {
5338 return Smi::FromInt(static_cast<int>(number));
5339 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005340 return Heap::NumberFromInt32(DoubleToInt32(number));
5341}
5342
5343
ager@chromium.org870a0b62008-11-04 11:43:05 +00005344// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5345// a small integer.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005346static MaybeObject* Runtime_NumberToSmi(Arguments args) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005347 NoHandleAllocation ha;
5348 ASSERT(args.length() == 1);
5349
5350 Object* obj = args[0];
5351 if (obj->IsSmi()) {
5352 return obj;
5353 }
5354 if (obj->IsHeapNumber()) {
5355 double value = HeapNumber::cast(obj)->value();
5356 int int_value = FastD2I(value);
5357 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5358 return Smi::FromInt(int_value);
5359 }
5360 }
5361 return Heap::nan_value();
5362}
5363
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005364
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005365static MaybeObject* Runtime_AllocateHeapNumber(Arguments args) {
5366 NoHandleAllocation ha;
5367 ASSERT(args.length() == 0);
5368 return Heap::AllocateHeapNumber(0);
5369}
5370
5371
lrn@chromium.org303ada72010-10-27 09:33:13 +00005372static MaybeObject* Runtime_NumberAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005373 NoHandleAllocation ha;
5374 ASSERT(args.length() == 2);
5375
5376 CONVERT_DOUBLE_CHECKED(x, args[0]);
5377 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005378 return Heap::NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005379}
5380
5381
lrn@chromium.org303ada72010-10-27 09:33:13 +00005382static MaybeObject* Runtime_NumberSub(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005383 NoHandleAllocation ha;
5384 ASSERT(args.length() == 2);
5385
5386 CONVERT_DOUBLE_CHECKED(x, args[0]);
5387 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005388 return Heap::NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005389}
5390
5391
lrn@chromium.org303ada72010-10-27 09:33:13 +00005392static MaybeObject* Runtime_NumberMul(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005393 NoHandleAllocation ha;
5394 ASSERT(args.length() == 2);
5395
5396 CONVERT_DOUBLE_CHECKED(x, args[0]);
5397 CONVERT_DOUBLE_CHECKED(y, args[1]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005398 return Heap::NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005399}
5400
5401
lrn@chromium.org303ada72010-10-27 09:33:13 +00005402static MaybeObject* Runtime_NumberUnaryMinus(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005403 NoHandleAllocation ha;
5404 ASSERT(args.length() == 1);
5405
5406 CONVERT_DOUBLE_CHECKED(x, args[0]);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00005407 return Heap::NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005408}
5409
5410
lrn@chromium.org303ada72010-10-27 09:33:13 +00005411static MaybeObject* Runtime_NumberAlloc(Arguments args) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005412 NoHandleAllocation ha;
5413 ASSERT(args.length() == 0);
5414
5415 return Heap::NumberFromDouble(9876543210.0);
5416}
5417
5418
lrn@chromium.org303ada72010-10-27 09:33:13 +00005419static MaybeObject* Runtime_NumberDiv(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005420 NoHandleAllocation ha;
5421 ASSERT(args.length() == 2);
5422
5423 CONVERT_DOUBLE_CHECKED(x, args[0]);
5424 CONVERT_DOUBLE_CHECKED(y, args[1]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005425 return Heap::NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005426}
5427
5428
lrn@chromium.org303ada72010-10-27 09:33:13 +00005429static MaybeObject* Runtime_NumberMod(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005430 NoHandleAllocation ha;
5431 ASSERT(args.length() == 2);
5432
5433 CONVERT_DOUBLE_CHECKED(x, args[0]);
5434 CONVERT_DOUBLE_CHECKED(y, args[1]);
5435
ager@chromium.org3811b432009-10-28 14:53:37 +00005436 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005437 // NumberFromDouble may return a Smi instead of a Number object
5438 return Heap::NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005439}
5440
5441
lrn@chromium.org303ada72010-10-27 09:33:13 +00005442static MaybeObject* Runtime_StringAdd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005443 NoHandleAllocation ha;
5444 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005445 CONVERT_CHECKED(String, str1, args[0]);
5446 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005447 Counters::string_add_runtime.Increment();
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005448 return Heap::AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005449}
5450
5451
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005452template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005453static inline void StringBuilderConcatHelper(String* special,
5454 sinkchar* sink,
5455 FixedArray* fixed_array,
5456 int array_length) {
5457 int position = 0;
5458 for (int i = 0; i < array_length; i++) {
5459 Object* element = fixed_array->get(i);
5460 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005461 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005462 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005463 int pos;
5464 int len;
5465 if (encoded_slice > 0) {
5466 // Position and length encoded in one smi.
5467 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5468 len = StringBuilderSubstringLength::decode(encoded_slice);
5469 } else {
5470 // Position and length encoded in two smis.
5471 Object* obj = fixed_array->get(++i);
5472 ASSERT(obj->IsSmi());
5473 pos = Smi::cast(obj)->value();
5474 len = -encoded_slice;
5475 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005476 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005477 sink + position,
5478 pos,
5479 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005480 position += len;
5481 } else {
5482 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005483 int element_length = string->length();
5484 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005485 position += element_length;
5486 }
5487 }
5488}
5489
5490
lrn@chromium.org303ada72010-10-27 09:33:13 +00005491static MaybeObject* Runtime_StringBuilderConcat(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005492 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005493 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005494 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005495 if (!args[1]->IsSmi()) {
5496 Top::context()->mark_out_of_memory();
5497 return Failure::OutOfMemoryException();
5498 }
5499 int array_length = Smi::cast(args[1])->value();
5500 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005501
5502 // This assumption is used by the slice encoding in one or two smis.
5503 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5504
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005505 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005506 if (!array->HasFastElements()) {
5507 return Top::Throw(Heap::illegal_argument_symbol());
5508 }
5509 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005510 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005511 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005512 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005513
5514 if (array_length == 0) {
5515 return Heap::empty_string();
5516 } else if (array_length == 1) {
5517 Object* first = fixed_array->get(0);
5518 if (first->IsString()) return first;
5519 }
5520
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005521 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005522 int position = 0;
5523 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005524 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005525 Object* elt = fixed_array->get(i);
5526 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005527 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005528 int smi_value = Smi::cast(elt)->value();
5529 int pos;
5530 int len;
5531 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005532 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005533 pos = StringBuilderSubstringPosition::decode(smi_value);
5534 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005535 } else {
5536 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005537 len = -smi_value;
5538 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005539 i++;
5540 if (i >= array_length) {
5541 return Top::Throw(Heap::illegal_argument_symbol());
5542 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005543 Object* next_smi = fixed_array->get(i);
5544 if (!next_smi->IsSmi()) {
5545 return Top::Throw(Heap::illegal_argument_symbol());
5546 }
5547 pos = Smi::cast(next_smi)->value();
5548 if (pos < 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005549 return Top::Throw(Heap::illegal_argument_symbol());
5550 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005551 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005552 ASSERT(pos >= 0);
5553 ASSERT(len >= 0);
5554 if (pos > special_length || len > special_length - pos) {
5555 return Top::Throw(Heap::illegal_argument_symbol());
5556 }
5557 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005558 } else if (elt->IsString()) {
5559 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005560 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005561 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005562 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005563 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005564 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005565 } else {
5566 return Top::Throw(Heap::illegal_argument_symbol());
5567 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005568 if (increment > String::kMaxLength - position) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005569 Top::context()->mark_out_of_memory();
5570 return Failure::OutOfMemoryException();
5571 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005572 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005573 }
5574
5575 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005576 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005577
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005578 if (ascii) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005579 { MaybeObject* maybe_object = Heap::AllocateRawAsciiString(length);
5580 if (!maybe_object->ToObject(&object)) return maybe_object;
5581 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005582 SeqAsciiString* answer = SeqAsciiString::cast(object);
5583 StringBuilderConcatHelper(special,
5584 answer->GetChars(),
5585 fixed_array,
5586 array_length);
5587 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005588 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005589 { MaybeObject* maybe_object = Heap::AllocateRawTwoByteString(length);
5590 if (!maybe_object->ToObject(&object)) return maybe_object;
5591 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005592 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
5593 StringBuilderConcatHelper(special,
5594 answer->GetChars(),
5595 fixed_array,
5596 array_length);
5597 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005598 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005599}
5600
5601
lrn@chromium.org303ada72010-10-27 09:33:13 +00005602static MaybeObject* Runtime_NumberOr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005603 NoHandleAllocation ha;
5604 ASSERT(args.length() == 2);
5605
5606 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5607 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5608 return Heap::NumberFromInt32(x | y);
5609}
5610
5611
lrn@chromium.org303ada72010-10-27 09:33:13 +00005612static MaybeObject* Runtime_NumberAnd(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005613 NoHandleAllocation ha;
5614 ASSERT(args.length() == 2);
5615
5616 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5617 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5618 return Heap::NumberFromInt32(x & y);
5619}
5620
5621
lrn@chromium.org303ada72010-10-27 09:33:13 +00005622static MaybeObject* Runtime_NumberXor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005623 NoHandleAllocation ha;
5624 ASSERT(args.length() == 2);
5625
5626 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5627 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5628 return Heap::NumberFromInt32(x ^ y);
5629}
5630
5631
lrn@chromium.org303ada72010-10-27 09:33:13 +00005632static MaybeObject* Runtime_NumberNot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005633 NoHandleAllocation ha;
5634 ASSERT(args.length() == 1);
5635
5636 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5637 return Heap::NumberFromInt32(~x);
5638}
5639
5640
lrn@chromium.org303ada72010-10-27 09:33:13 +00005641static MaybeObject* Runtime_NumberShl(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005642 NoHandleAllocation ha;
5643 ASSERT(args.length() == 2);
5644
5645 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5646 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5647 return Heap::NumberFromInt32(x << (y & 0x1f));
5648}
5649
5650
lrn@chromium.org303ada72010-10-27 09:33:13 +00005651static MaybeObject* Runtime_NumberShr(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005652 NoHandleAllocation ha;
5653 ASSERT(args.length() == 2);
5654
5655 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
5656 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5657 return Heap::NumberFromUint32(x >> (y & 0x1f));
5658}
5659
5660
lrn@chromium.org303ada72010-10-27 09:33:13 +00005661static MaybeObject* Runtime_NumberSar(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005662 NoHandleAllocation ha;
5663 ASSERT(args.length() == 2);
5664
5665 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
5666 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
5667 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
5668}
5669
5670
lrn@chromium.org303ada72010-10-27 09:33:13 +00005671static MaybeObject* Runtime_NumberEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005672 NoHandleAllocation ha;
5673 ASSERT(args.length() == 2);
5674
5675 CONVERT_DOUBLE_CHECKED(x, args[0]);
5676 CONVERT_DOUBLE_CHECKED(y, args[1]);
5677 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
5678 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
5679 if (x == y) return Smi::FromInt(EQUAL);
5680 Object* result;
5681 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
5682 result = Smi::FromInt(EQUAL);
5683 } else {
5684 result = Smi::FromInt(NOT_EQUAL);
5685 }
5686 return result;
5687}
5688
5689
lrn@chromium.org303ada72010-10-27 09:33:13 +00005690static MaybeObject* Runtime_StringEquals(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005691 NoHandleAllocation ha;
5692 ASSERT(args.length() == 2);
5693
5694 CONVERT_CHECKED(String, x, args[0]);
5695 CONVERT_CHECKED(String, y, args[1]);
5696
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005697 bool not_equal = !x->Equals(y);
5698 // This is slightly convoluted because the value that signifies
5699 // equality is 0 and inequality is 1 so we have to negate the result
5700 // from String::Equals.
5701 ASSERT(not_equal == 0 || not_equal == 1);
5702 STATIC_CHECK(EQUAL == 0);
5703 STATIC_CHECK(NOT_EQUAL == 1);
5704 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005705}
5706
5707
lrn@chromium.org303ada72010-10-27 09:33:13 +00005708static MaybeObject* Runtime_NumberCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005709 NoHandleAllocation ha;
5710 ASSERT(args.length() == 3);
5711
5712 CONVERT_DOUBLE_CHECKED(x, args[0]);
5713 CONVERT_DOUBLE_CHECKED(y, args[1]);
5714 if (isnan(x) || isnan(y)) return args[2];
5715 if (x == y) return Smi::FromInt(EQUAL);
5716 if (isless(x, y)) return Smi::FromInt(LESS);
5717 return Smi::FromInt(GREATER);
5718}
5719
5720
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005721// Compare two Smis as if they were converted to strings and then
5722// compared lexicographically.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005723static MaybeObject* Runtime_SmiLexicographicCompare(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005724 NoHandleAllocation ha;
5725 ASSERT(args.length() == 2);
5726
5727 // Arrays for the individual characters of the two Smis. Smis are
5728 // 31 bit integers and 10 decimal digits are therefore enough.
5729 static int x_elms[10];
5730 static int y_elms[10];
5731
5732 // Extract the integer values from the Smis.
5733 CONVERT_CHECKED(Smi, x, args[0]);
5734 CONVERT_CHECKED(Smi, y, args[1]);
5735 int x_value = x->value();
5736 int y_value = y->value();
5737
5738 // If the integers are equal so are the string representations.
5739 if (x_value == y_value) return Smi::FromInt(EQUAL);
5740
5741 // If one of the integers are zero the normal integer order is the
5742 // same as the lexicographic order of the string representations.
5743 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
5744
ager@chromium.org32912102009-01-16 10:38:43 +00005745 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005746 // smallest because the char code of '-' is less than the char code
5747 // of any digit. Otherwise, we make both values positive.
5748 if (x_value < 0 || y_value < 0) {
5749 if (y_value >= 0) return Smi::FromInt(LESS);
5750 if (x_value >= 0) return Smi::FromInt(GREATER);
5751 x_value = -x_value;
5752 y_value = -y_value;
5753 }
5754
5755 // Convert the integers to arrays of their decimal digits.
5756 int x_index = 0;
5757 int y_index = 0;
5758 while (x_value > 0) {
5759 x_elms[x_index++] = x_value % 10;
5760 x_value /= 10;
5761 }
5762 while (y_value > 0) {
5763 y_elms[y_index++] = y_value % 10;
5764 y_value /= 10;
5765 }
5766
5767 // Loop through the arrays of decimal digits finding the first place
5768 // where they differ.
5769 while (--x_index >= 0 && --y_index >= 0) {
5770 int diff = x_elms[x_index] - y_elms[y_index];
5771 if (diff != 0) return Smi::FromInt(diff);
5772 }
5773
5774 // If one array is a suffix of the other array, the longest array is
5775 // the representation of the largest of the Smis in the
5776 // lexicographic ordering.
5777 return Smi::FromInt(x_index - y_index);
5778}
5779
5780
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005781static Object* StringInputBufferCompare(String* x, String* y) {
5782 static StringInputBuffer bufx;
5783 static StringInputBuffer bufy;
5784 bufx.Reset(x);
5785 bufy.Reset(y);
5786 while (bufx.has_more() && bufy.has_more()) {
5787 int d = bufx.GetNext() - bufy.GetNext();
5788 if (d < 0) return Smi::FromInt(LESS);
5789 else if (d > 0) return Smi::FromInt(GREATER);
5790 }
5791
5792 // x is (non-trivial) prefix of y:
5793 if (bufy.has_more()) return Smi::FromInt(LESS);
5794 // y is prefix of x:
5795 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
5796}
5797
5798
5799static Object* FlatStringCompare(String* x, String* y) {
5800 ASSERT(x->IsFlat());
5801 ASSERT(y->IsFlat());
5802 Object* equal_prefix_result = Smi::FromInt(EQUAL);
5803 int prefix_length = x->length();
5804 if (y->length() < prefix_length) {
5805 prefix_length = y->length();
5806 equal_prefix_result = Smi::FromInt(GREATER);
5807 } else if (y->length() > prefix_length) {
5808 equal_prefix_result = Smi::FromInt(LESS);
5809 }
5810 int r;
5811 if (x->IsAsciiRepresentation()) {
5812 Vector<const char> x_chars = x->ToAsciiVector();
5813 if (y->IsAsciiRepresentation()) {
5814 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005815 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005816 } else {
5817 Vector<const uc16> y_chars = y->ToUC16Vector();
5818 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5819 }
5820 } else {
5821 Vector<const uc16> x_chars = x->ToUC16Vector();
5822 if (y->IsAsciiRepresentation()) {
5823 Vector<const char> y_chars = y->ToAsciiVector();
5824 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5825 } else {
5826 Vector<const uc16> y_chars = y->ToUC16Vector();
5827 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
5828 }
5829 }
5830 Object* result;
5831 if (r == 0) {
5832 result = equal_prefix_result;
5833 } else {
5834 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
5835 }
5836 ASSERT(result == StringInputBufferCompare(x, y));
5837 return result;
5838}
5839
5840
lrn@chromium.org303ada72010-10-27 09:33:13 +00005841static MaybeObject* Runtime_StringCompare(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005842 NoHandleAllocation ha;
5843 ASSERT(args.length() == 2);
5844
5845 CONVERT_CHECKED(String, x, args[0]);
5846 CONVERT_CHECKED(String, y, args[1]);
5847
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005848 Counters::string_compare_runtime.Increment();
5849
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005850 // A few fast case tests before we flatten.
5851 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005852 if (y->length() == 0) {
5853 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005854 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005855 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005856 return Smi::FromInt(LESS);
5857 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005858
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005859 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005860 if (d < 0) return Smi::FromInt(LESS);
5861 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005862
lrn@chromium.org303ada72010-10-27 09:33:13 +00005863 Object* obj;
5864 { MaybeObject* maybe_obj = Heap::PrepareForCompare(x);
5865 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5866 }
5867 { MaybeObject* maybe_obj = Heap::PrepareForCompare(y);
5868 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5869 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005870
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005871 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
5872 : StringInputBufferCompare(x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005873}
5874
5875
lrn@chromium.org303ada72010-10-27 09:33:13 +00005876static MaybeObject* Runtime_Math_acos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005877 NoHandleAllocation ha;
5878 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005879 Counters::math_acos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005880
5881 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005882 return TranscendentalCache::Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005883}
5884
5885
lrn@chromium.org303ada72010-10-27 09:33:13 +00005886static MaybeObject* Runtime_Math_asin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005887 NoHandleAllocation ha;
5888 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005889 Counters::math_asin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005890
5891 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005892 return TranscendentalCache::Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005893}
5894
5895
lrn@chromium.org303ada72010-10-27 09:33:13 +00005896static MaybeObject* Runtime_Math_atan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005897 NoHandleAllocation ha;
5898 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005899 Counters::math_atan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005900
5901 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005902 return TranscendentalCache::Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005903}
5904
5905
lrn@chromium.org303ada72010-10-27 09:33:13 +00005906static MaybeObject* Runtime_Math_atan2(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005907 NoHandleAllocation ha;
5908 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005909 Counters::math_atan2.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005910
5911 CONVERT_DOUBLE_CHECKED(x, args[0]);
5912 CONVERT_DOUBLE_CHECKED(y, args[1]);
5913 double result;
5914 if (isinf(x) && isinf(y)) {
5915 // Make sure that the result in case of two infinite arguments
5916 // is a multiple of Pi / 4. The sign of the result is determined
5917 // by the first argument (x) and the sign of the second argument
5918 // determines the multiplier: one or three.
5919 static double kPiDividedBy4 = 0.78539816339744830962;
5920 int multiplier = (x < 0) ? -1 : 1;
5921 if (y < 0) multiplier *= 3;
5922 result = multiplier * kPiDividedBy4;
5923 } else {
5924 result = atan2(x, y);
5925 }
5926 return Heap::AllocateHeapNumber(result);
5927}
5928
5929
lrn@chromium.org303ada72010-10-27 09:33:13 +00005930static MaybeObject* Runtime_Math_ceil(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005931 NoHandleAllocation ha;
5932 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005933 Counters::math_ceil.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005934
5935 CONVERT_DOUBLE_CHECKED(x, args[0]);
5936 return Heap::NumberFromDouble(ceiling(x));
5937}
5938
5939
lrn@chromium.org303ada72010-10-27 09:33:13 +00005940static MaybeObject* Runtime_Math_cos(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005941 NoHandleAllocation ha;
5942 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005943 Counters::math_cos.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005944
5945 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005946 return TranscendentalCache::Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005947}
5948
5949
lrn@chromium.org303ada72010-10-27 09:33:13 +00005950static MaybeObject* Runtime_Math_exp(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005951 NoHandleAllocation ha;
5952 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005953 Counters::math_exp.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005954
5955 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005956 return TranscendentalCache::Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005957}
5958
5959
lrn@chromium.org303ada72010-10-27 09:33:13 +00005960static MaybeObject* Runtime_Math_floor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005961 NoHandleAllocation ha;
5962 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005963 Counters::math_floor.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005964
5965 CONVERT_DOUBLE_CHECKED(x, args[0]);
5966 return Heap::NumberFromDouble(floor(x));
5967}
5968
5969
lrn@chromium.org303ada72010-10-27 09:33:13 +00005970static MaybeObject* Runtime_Math_log(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005971 NoHandleAllocation ha;
5972 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005973 Counters::math_log.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005974
5975 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00005976 return TranscendentalCache::Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005977}
5978
5979
ager@chromium.org5aa501c2009-06-23 07:57:28 +00005980// Helper function to compute x^y, where y is known to be an
5981// integer. Uses binary decomposition to limit the number of
5982// multiplications; see the discussion in "Hacker's Delight" by Henry
5983// S. Warren, Jr., figure 11-6, page 213.
5984static double powi(double x, int y) {
5985 ASSERT(y != kMinInt);
5986 unsigned n = (y < 0) ? -y : y;
5987 double m = x;
5988 double p = 1;
5989 while (true) {
5990 if ((n & 1) != 0) p *= m;
5991 n >>= 1;
5992 if (n == 0) {
5993 if (y < 0) {
5994 // Unfortunately, we have to be careful when p has reached
5995 // infinity in the computation, because sometimes the higher
5996 // internal precision in the pow() implementation would have
5997 // given us a finite p. This happens very rarely.
5998 double result = 1.0 / p;
5999 return (result == 0 && isinf(p))
6000 ? pow(x, static_cast<double>(y)) // Avoid pow(double, int).
6001 : result;
6002 } else {
6003 return p;
6004 }
6005 }
6006 m *= m;
6007 }
6008}
6009
6010
lrn@chromium.org303ada72010-10-27 09:33:13 +00006011static MaybeObject* Runtime_Math_pow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006012 NoHandleAllocation ha;
6013 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006014 Counters::math_pow.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006015
6016 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006017
6018 // If the second argument is a smi, it is much faster to call the
6019 // custom powi() function than the generic pow().
6020 if (args[1]->IsSmi()) {
6021 int y = Smi::cast(args[1])->value();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00006022 return Heap::NumberFromDouble(powi(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006023 }
6024
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006025 CONVERT_DOUBLE_CHECKED(y, args[1]);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00006026
6027 if (!isinf(x)) {
6028 if (y == 0.5) {
6029 // It's not uncommon to use Math.pow(x, 0.5) to compute the
6030 // square root of a number. To speed up such computations, we
6031 // explictly check for this case and use the sqrt() function
6032 // which is faster than pow().
6033 return Heap::AllocateHeapNumber(sqrt(x));
6034 } else if (y == -0.5) {
6035 // Optimized using Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5).
6036 return Heap::AllocateHeapNumber(1.0 / sqrt(x));
6037 }
6038 }
6039
6040 if (y == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006041 return Smi::FromInt(1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006042 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
6043 return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006044 } else {
6045 return Heap::AllocateHeapNumber(pow(x, y));
6046 }
6047}
6048
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006049// Fast version of Math.pow if we know that y is not an integer and
6050// y is not -0.5 or 0.5. Used as slowcase from codegen.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006051static MaybeObject* Runtime_Math_pow_cfunction(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006052 NoHandleAllocation ha;
6053 ASSERT(args.length() == 2);
6054 CONVERT_DOUBLE_CHECKED(x, args[0]);
6055 CONVERT_DOUBLE_CHECKED(y, args[1]);
6056 if (y == 0) {
6057 return Smi::FromInt(1);
6058 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
6059 return Heap::nan_value();
6060 } else {
6061 return Heap::AllocateHeapNumber(pow(x, y));
6062 }
6063}
6064
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006065
lrn@chromium.org303ada72010-10-27 09:33:13 +00006066static MaybeObject* Runtime_RoundNumber(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006067 NoHandleAllocation ha;
6068 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006069 Counters::math_round.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006070
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006071 if (!args[0]->IsHeapNumber()) {
6072 // Must be smi. Return the argument unchanged for all the other types
6073 // to make fuzz-natives test happy.
6074 return args[0];
6075 }
6076
6077 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6078
6079 double value = number->value();
6080 int exponent = number->get_exponent();
6081 int sign = number->get_sign();
6082
6083 // We compare with kSmiValueSize - 3 because (2^30 - 0.1) has exponent 29 and
6084 // should be rounded to 2^30, which is not smi.
6085 if (!sign && exponent <= kSmiValueSize - 3) {
6086 return Smi::FromInt(static_cast<int>(value + 0.5));
6087 }
6088
6089 // If the magnitude is big enough, there's no place for fraction part. If we
6090 // try to add 0.5 to this number, 1.0 will be added instead.
6091 if (exponent >= 52) {
6092 return number;
6093 }
6094
6095 if (sign && value >= -0.5) return Heap::minus_zero_value();
6096
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006097 // Do not call NumberFromDouble() to avoid extra checks.
6098 return Heap::AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006099}
6100
6101
lrn@chromium.org303ada72010-10-27 09:33:13 +00006102static MaybeObject* Runtime_Math_sin(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006103 NoHandleAllocation ha;
6104 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006105 Counters::math_sin.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006106
6107 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006108 return TranscendentalCache::Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006109}
6110
6111
lrn@chromium.org303ada72010-10-27 09:33:13 +00006112static MaybeObject* Runtime_Math_sqrt(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006113 NoHandleAllocation ha;
6114 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006115 Counters::math_sqrt.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006116
6117 CONVERT_DOUBLE_CHECKED(x, args[0]);
6118 return Heap::AllocateHeapNumber(sqrt(x));
6119}
6120
6121
lrn@chromium.org303ada72010-10-27 09:33:13 +00006122static MaybeObject* Runtime_Math_tan(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006123 NoHandleAllocation ha;
6124 ASSERT(args.length() == 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006125 Counters::math_tan.Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006126
6127 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006128 return TranscendentalCache::Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006129}
6130
6131
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006132static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006133 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6134 181, 212, 243, 273, 304, 334};
6135 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6136 182, 213, 244, 274, 305, 335};
6137
6138 year += month / 12;
6139 month %= 12;
6140 if (month < 0) {
6141 year--;
6142 month += 12;
6143 }
6144
6145 ASSERT(month >= 0);
6146 ASSERT(month < 12);
6147
6148 // year_delta is an arbitrary number such that:
6149 // a) year_delta = -1 (mod 400)
6150 // b) year + year_delta > 0 for years in the range defined by
6151 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6152 // Jan 1 1970. This is required so that we don't run into integer
6153 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006154 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006155 // operations.
6156 static const int year_delta = 399999;
6157 static const int base_day = 365 * (1970 + year_delta) +
6158 (1970 + year_delta) / 4 -
6159 (1970 + year_delta) / 100 +
6160 (1970 + year_delta) / 400;
6161
6162 int year1 = year + year_delta;
6163 int day_from_year = 365 * year1 +
6164 year1 / 4 -
6165 year1 / 100 +
6166 year1 / 400 -
6167 base_day;
6168
6169 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006170 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006171 }
6172
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006173 return day_from_year + day_from_month_leap[month] + day - 1;
6174}
6175
6176
lrn@chromium.org303ada72010-10-27 09:33:13 +00006177static MaybeObject* Runtime_DateMakeDay(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006178 NoHandleAllocation ha;
6179 ASSERT(args.length() == 3);
6180
6181 CONVERT_SMI_CHECKED(year, args[0]);
6182 CONVERT_SMI_CHECKED(month, args[1]);
6183 CONVERT_SMI_CHECKED(date, args[2]);
6184
6185 return Smi::FromInt(MakeDay(year, month, date));
6186}
6187
6188
6189static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6190static const int kDaysIn4Years = 4 * 365 + 1;
6191static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6192static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6193static const int kDays1970to2000 = 30 * 365 + 7;
6194static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6195 kDays1970to2000;
6196static const int kYearsOffset = 400000;
6197
6198static const char kDayInYear[] = {
6199 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6200 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6201 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6202 22, 23, 24, 25, 26, 27, 28,
6203 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6204 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6205 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6206 22, 23, 24, 25, 26, 27, 28, 29, 30,
6207 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6208 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6209 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6210 22, 23, 24, 25, 26, 27, 28, 29, 30,
6211 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6212 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6213 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6214 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6215 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6216 22, 23, 24, 25, 26, 27, 28, 29, 30,
6217 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6218 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6219 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6220 22, 23, 24, 25, 26, 27, 28, 29, 30,
6221 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6222 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6223
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, 31,
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,
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 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6239 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6240 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6241 22, 23, 24, 25, 26, 27, 28, 29, 30,
6242 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6243 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6244 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6245 22, 23, 24, 25, 26, 27, 28, 29, 30,
6246 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6247 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6248
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, 31,
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,
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 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6264 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6265 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6266 22, 23, 24, 25, 26, 27, 28, 29, 30,
6267 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6268 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6269 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6270 22, 23, 24, 25, 26, 27, 28, 29, 30,
6271 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6272 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6273
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, 31,
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,
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 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6289 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6290 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6291 22, 23, 24, 25, 26, 27, 28, 29, 30,
6292 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6293 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6294 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6295 22, 23, 24, 25, 26, 27, 28, 29, 30,
6296 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6297 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6298
6299static const char kMonthInYear[] = {
6300 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,
6301 0, 0, 0, 0, 0, 0,
6302 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,
6303 1, 1, 1,
6304 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,
6305 2, 2, 2, 2, 2, 2,
6306 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,
6307 3, 3, 3, 3, 3,
6308 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,
6309 4, 4, 4, 4, 4, 4,
6310 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,
6311 5, 5, 5, 5, 5,
6312 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,
6313 6, 6, 6, 6, 6, 6,
6314 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,
6315 7, 7, 7, 7, 7, 7,
6316 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,
6317 8, 8, 8, 8, 8,
6318 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,
6319 9, 9, 9, 9, 9, 9,
6320 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6321 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6322 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6323 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6324
6325 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,
6326 0, 0, 0, 0, 0, 0,
6327 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,
6328 1, 1, 1,
6329 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,
6330 2, 2, 2, 2, 2, 2,
6331 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,
6332 3, 3, 3, 3, 3,
6333 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,
6334 4, 4, 4, 4, 4, 4,
6335 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,
6336 5, 5, 5, 5, 5,
6337 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,
6338 6, 6, 6, 6, 6, 6,
6339 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,
6340 7, 7, 7, 7, 7, 7,
6341 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,
6342 8, 8, 8, 8, 8,
6343 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,
6344 9, 9, 9, 9, 9, 9,
6345 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6346 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6347 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6348 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6349
6350 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,
6351 0, 0, 0, 0, 0, 0,
6352 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,
6353 1, 1, 1, 1,
6354 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,
6355 2, 2, 2, 2, 2, 2,
6356 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,
6357 3, 3, 3, 3, 3,
6358 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,
6359 4, 4, 4, 4, 4, 4,
6360 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,
6361 5, 5, 5, 5, 5,
6362 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,
6363 6, 6, 6, 6, 6, 6,
6364 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,
6365 7, 7, 7, 7, 7, 7,
6366 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,
6367 8, 8, 8, 8, 8,
6368 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,
6369 9, 9, 9, 9, 9, 9,
6370 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6371 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6372 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6373 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6374
6375 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,
6376 0, 0, 0, 0, 0, 0,
6377 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,
6378 1, 1, 1,
6379 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,
6380 2, 2, 2, 2, 2, 2,
6381 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,
6382 3, 3, 3, 3, 3,
6383 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,
6384 4, 4, 4, 4, 4, 4,
6385 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,
6386 5, 5, 5, 5, 5,
6387 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,
6388 6, 6, 6, 6, 6, 6,
6389 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,
6390 7, 7, 7, 7, 7, 7,
6391 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,
6392 8, 8, 8, 8, 8,
6393 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,
6394 9, 9, 9, 9, 9, 9,
6395 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6396 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6397 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6398 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6399
6400
6401// This function works for dates from 1970 to 2099.
6402static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006403 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006404#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006405 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006406#endif
6407
6408 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6409 date %= kDaysIn4Years;
6410
6411 month = kMonthInYear[date];
6412 day = kDayInYear[date];
6413
6414 ASSERT(MakeDay(year, month, day) == save_date);
6415}
6416
6417
6418static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006419 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006420#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006421 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006422#endif
6423
6424 date += kDaysOffset;
6425 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6426 date %= kDaysIn400Years;
6427
6428 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6429
6430 date--;
6431 int yd1 = date / kDaysIn100Years;
6432 date %= kDaysIn100Years;
6433 year += 100 * yd1;
6434
6435 date++;
6436 int yd2 = date / kDaysIn4Years;
6437 date %= kDaysIn4Years;
6438 year += 4 * yd2;
6439
6440 date--;
6441 int yd3 = date / 365;
6442 date %= 365;
6443 year += yd3;
6444
6445 bool is_leap = (!yd1 || yd2) && !yd3;
6446
6447 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006448 ASSERT(is_leap || (date >= 0));
6449 ASSERT((date < 365) || (is_leap && (date < 366)));
6450 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6451 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6452 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006453
6454 if (is_leap) {
6455 day = kDayInYear[2*365 + 1 + date];
6456 month = kMonthInYear[2*365 + 1 + date];
6457 } else {
6458 day = kDayInYear[date];
6459 month = kMonthInYear[date];
6460 }
6461
6462 ASSERT(MakeDay(year, month, day) == save_date);
6463}
6464
6465
6466static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006467 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006468 if (date >= 0 && date < 32 * kDaysIn4Years) {
6469 DateYMDFromTimeAfter1970(date, year, month, day);
6470 } else {
6471 DateYMDFromTimeSlow(date, year, month, day);
6472 }
6473}
6474
6475
lrn@chromium.org303ada72010-10-27 09:33:13 +00006476static MaybeObject* Runtime_DateYMDFromTime(Arguments args) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006477 NoHandleAllocation ha;
6478 ASSERT(args.length() == 2);
6479
6480 CONVERT_DOUBLE_CHECKED(t, args[0]);
6481 CONVERT_CHECKED(JSArray, res_array, args[1]);
6482
6483 int year, month, day;
6484 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
6485
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006486 RUNTIME_ASSERT(res_array->elements()->map() == Heap::fixed_array_map());
6487 FixedArray* elms = FixedArray::cast(res_array->elements());
6488 RUNTIME_ASSERT(elms->length() == 3);
6489
6490 elms->set(0, Smi::FromInt(year));
6491 elms->set(1, Smi::FromInt(month));
6492 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006493
6494 return Heap::undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006495}
6496
6497
lrn@chromium.org303ada72010-10-27 09:33:13 +00006498static MaybeObject* Runtime_NewArgumentsFast(Arguments args) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006499 NoHandleAllocation ha;
6500 ASSERT(args.length() == 3);
6501
6502 JSFunction* callee = JSFunction::cast(args[0]);
6503 Object** parameters = reinterpret_cast<Object**>(args[1]);
6504 const int length = Smi::cast(args[2])->value();
6505
lrn@chromium.org303ada72010-10-27 09:33:13 +00006506 Object* result;
6507 { MaybeObject* maybe_result = Heap::AllocateArgumentsObject(callee, length);
6508 if (!maybe_result->ToObject(&result)) return maybe_result;
6509 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006510 // Allocate the elements if needed.
6511 if (length > 0) {
6512 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006513 Object* obj;
6514 { MaybeObject* maybe_obj = Heap::AllocateRawFixedArray(length);
6515 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6516 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006517
6518 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006519 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
6520 array->set_map(Heap::fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006521 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006522
6523 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00006524 for (int i = 0; i < length; i++) {
6525 array->set(i, *--parameters, mode);
6526 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006527 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00006528 }
6529 return result;
6530}
6531
6532
lrn@chromium.org303ada72010-10-27 09:33:13 +00006533static MaybeObject* Runtime_NewClosure(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006534 HandleScope scope;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006535 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00006536 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00006537 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006538 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006539
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006540 // Allocate global closures in old space and allocate local closures
6541 // in new space. Additionally pretenure closures that are assigned
6542 // directly to properties.
6543 pretenure = pretenure || (context->global_context() == *context);
6544 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006545 Handle<JSFunction> result =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00006546 Factory::NewFunctionFromSharedFunctionInfo(shared,
6547 context,
6548 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006549 return *result;
6550}
6551
lrn@chromium.org303ada72010-10-27 09:33:13 +00006552static MaybeObject* Runtime_NewObjectFromBound(Arguments args) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006553 HandleScope scope;
6554 ASSERT(args.length() == 2);
6555 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6556 CONVERT_ARG_CHECKED(JSArray, params, 1);
6557
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006558 RUNTIME_ASSERT(params->HasFastElements());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006559 FixedArray* fixed = FixedArray::cast(params->elements());
6560
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006561 int fixed_length = Smi::cast(params->length())->value();
6562 SmartPointer<Object**> param_data(NewArray<Object**>(fixed_length));
6563 for (int i = 0; i < fixed_length; i++) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006564 Handle<Object> val = Handle<Object>(fixed->get(i));
6565 param_data[i] = val.location();
6566 }
6567
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006568 bool exception = false;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006569 Handle<Object> result = Execution::New(
whesse@chromium.orge90029b2010-08-02 11:52:17 +00006570 function, fixed_length, *param_data, &exception);
6571 if (exception) {
6572 return Failure::Exception();
6573 }
6574 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00006575 return *result;
6576}
6577
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006578
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006579static void TrySettingInlineConstructStub(Handle<JSFunction> function) {
ager@chromium.org5c838252010-02-19 08:53:10 +00006580 Handle<Object> prototype = Factory::null_value();
6581 if (function->has_instance_prototype()) {
6582 prototype = Handle<Object>(function->instance_prototype());
6583 }
6584 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006585 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006586 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006587 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006588 function->shared()->set_construct_stub(
6589 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006590 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006591 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006592}
6593
6594
lrn@chromium.org303ada72010-10-27 09:33:13 +00006595static MaybeObject* Runtime_NewObject(Arguments args) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006596 HandleScope scope;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006597 ASSERT(args.length() == 1);
6598
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006599 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006600
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006601 // If the constructor isn't a proper function we throw a type error.
6602 if (!constructor->IsJSFunction()) {
6603 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6604 Handle<Object> type_error =
6605 Factory::NewTypeError("not_constructor", arguments);
6606 return Top::Throw(*type_error);
6607 }
6608
6609 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006610
6611 // If function should not have prototype, construction is not allowed. In this
6612 // case generated code bailouts here, since function has no initial_map.
6613 if (!function->should_have_prototype()) {
6614 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
6615 Handle<Object> type_error =
6616 Factory::NewTypeError("not_constructor", arguments);
6617 return Top::Throw(*type_error);
6618 }
6619
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006620#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006621 // Handle stepping into constructors if step into is active.
6622 if (Debug::StepInActive()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006623 Debug::HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006624 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006625#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006626
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006627 if (function->has_initial_map()) {
6628 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006629 // The 'Function' function ignores the receiver object when
6630 // called using 'new' and creates a new JSFunction object that
6631 // is returned. The receiver object is only used for error
6632 // reporting if an error occurs when constructing the new
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006633 // JSFunction. Factory::NewJSObject() should not be used to
6634 // allocate JSFunctions since it does not properly initialize
6635 // the shared part of the function. Since the receiver is
6636 // ignored anyway, we use the global object as the receiver
6637 // instead of a new JSFunction object. This way, errors are
6638 // reported the same way whether or not 'Function' is called
6639 // using 'new'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006640 return Top::context()->global();
6641 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006642 }
6643
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006644 // The function should be compiled for the optimization hints to be
6645 // available. We cannot use EnsureCompiled because that forces a
6646 // compilation through the shared function info which makes it
6647 // impossible for us to optimize.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006648 Handle<SharedFunctionInfo> shared(function->shared());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006649 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006650
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006651 if (!function->has_initial_map() &&
6652 shared->IsInobjectSlackTrackingInProgress()) {
6653 // The tracking is already in progress for another function. We can only
6654 // track one initial_map at a time, so we force the completion before the
6655 // function is called as a constructor for the first time.
6656 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006657 }
6658
6659 bool first_allocation = !shared->live_objects_may_exist();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006660 Handle<JSObject> result = Factory::NewJSObject(function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006661 // Delay setting the stub if inobject slack tracking is in progress.
6662 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
6663 TrySettingInlineConstructStub(function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006664 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006665
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006666 Counters::constructed_objects.Increment();
6667 Counters::constructed_objects_runtime.Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006668
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006669 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006670}
6671
6672
lrn@chromium.org303ada72010-10-27 09:33:13 +00006673static MaybeObject* Runtime_FinalizeInstanceSize(Arguments args) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006674 HandleScope scope;
6675 ASSERT(args.length() == 1);
6676
6677 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6678 function->shared()->CompleteInobjectSlackTracking();
6679 TrySettingInlineConstructStub(function);
6680
6681 return Heap::undefined_value();
6682}
6683
6684
lrn@chromium.org303ada72010-10-27 09:33:13 +00006685static MaybeObject* Runtime_LazyCompile(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006686 HandleScope scope;
6687 ASSERT(args.length() == 1);
6688
6689 Handle<JSFunction> function = args.at<JSFunction>(0);
6690#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00006691 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006692 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006693 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006694 PrintF("]\n");
6695 }
6696#endif
6697
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006698 // Compile the target function. Here we compile using CompileLazyInLoop in
6699 // order to get the optimized version. This helps code like delta-blue
6700 // that calls performance-critical routines through constructors. A
6701 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
6702 // direct call. Since the in-loop tracking takes place through CallICs
6703 // this means that things called through constructors are never known to
6704 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006705 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00006706 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006707 return Failure::Exception();
6708 }
6709
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006710 // All done. Return the compiled code.
6711 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006712 return function->code();
6713}
6714
6715
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006716static MaybeObject* Runtime_LazyRecompile(Arguments args) {
6717 HandleScope scope;
6718 ASSERT(args.length() == 1);
6719 Handle<JSFunction> function = args.at<JSFunction>(0);
6720 // If the function is not optimizable or debugger is active continue using the
6721 // code from the full compiler.
6722 if (!function->shared()->code()->optimizable() ||
6723 Debug::has_break_points()) {
6724 function->ReplaceCode(function->shared()->code());
6725 return function->code();
6726 }
6727 if (CompileOptimized(function, AstNode::kNoNumber)) {
6728 return function->code();
6729 }
6730 function->ReplaceCode(function->shared()->code());
6731 return Failure::Exception();
6732}
6733
6734
6735static MaybeObject* Runtime_NotifyDeoptimized(Arguments args) {
6736 HandleScope scope;
6737 ASSERT(args.length() == 1);
6738 RUNTIME_ASSERT(args[0]->IsSmi());
6739 Deoptimizer::BailoutType type =
6740 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
6741 Deoptimizer* deoptimizer = Deoptimizer::Grab();
6742 ASSERT(Heap::IsAllocationAllowed());
6743 int frames = deoptimizer->output_count();
6744
6745 JavaScriptFrameIterator it;
6746 JavaScriptFrame* frame = NULL;
6747 for (int i = 0; i < frames; i++) {
6748 if (i != 0) it.Advance();
6749 frame = it.frame();
6750 deoptimizer->InsertHeapNumberValues(frames - i - 1, frame);
6751 }
6752 delete deoptimizer;
6753
6754 RUNTIME_ASSERT(frame->function()->IsJSFunction());
6755 Handle<JSFunction> function(JSFunction::cast(frame->function()));
6756 Handle<Object> arguments;
6757 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
6758 if (frame->GetExpression(i) == Heap::the_hole_value()) {
6759 if (arguments.is_null()) {
6760 // FunctionGetArguments can't throw an exception, so cast away the
6761 // doubt with an assert.
6762 arguments = Handle<Object>(
6763 Accessors::FunctionGetArguments(*function,
6764 NULL)->ToObjectUnchecked());
6765 ASSERT(*arguments != Heap::null_value());
6766 ASSERT(*arguments != Heap::undefined_value());
6767 }
6768 frame->SetExpression(i, *arguments);
6769 }
6770 }
6771
6772 CompilationCache::MarkForLazyOptimizing(function);
6773 if (type == Deoptimizer::EAGER) {
6774 RUNTIME_ASSERT(function->IsOptimized());
6775 } else {
6776 RUNTIME_ASSERT(!function->IsOptimized());
6777 }
6778
6779 // Avoid doing too much work when running with --always-opt and keep
6780 // the optimized code around.
6781 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
6782 return Heap::undefined_value();
6783 }
6784
6785 // Count the number of optimized activations of the function.
6786 int activations = 0;
6787 while (!it.done()) {
6788 JavaScriptFrame* frame = it.frame();
6789 if (frame->is_optimized() && frame->function() == *function) {
6790 activations++;
6791 }
6792 it.Advance();
6793 }
6794
6795 // TODO(kasperl): For now, we cannot support removing the optimized
6796 // code when we have recursive invocations of the same function.
6797 if (activations == 0) {
6798 if (FLAG_trace_deopt) {
6799 PrintF("[removing optimized code for: ");
6800 function->PrintName();
6801 PrintF("]\n");
6802 }
6803 function->ReplaceCode(function->shared()->code());
6804 }
6805 return Heap::undefined_value();
6806}
6807
6808
6809static MaybeObject* Runtime_NotifyOSR(Arguments args) {
6810 Deoptimizer* deoptimizer = Deoptimizer::Grab();
6811 delete deoptimizer;
6812 return Heap::undefined_value();
6813}
6814
6815
6816static MaybeObject* Runtime_DeoptimizeFunction(Arguments args) {
6817 HandleScope scope;
6818 ASSERT(args.length() == 1);
6819 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6820 if (!function->IsOptimized()) return Heap::undefined_value();
6821
6822 Deoptimizer::DeoptimizeFunction(*function);
6823
6824 return Heap::undefined_value();
6825}
6826
6827
6828static MaybeObject* Runtime_CompileForOnStackReplacement(Arguments args) {
6829 HandleScope scope;
6830 ASSERT(args.length() == 1);
6831 CONVERT_ARG_CHECKED(JSFunction, function, 0);
6832
6833 // We're not prepared to handle a function with arguments object.
6834 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
6835
6836 // We have hit a back edge in an unoptimized frame for a function that was
6837 // selected for on-stack replacement. Find the unoptimized code object.
6838 Handle<Code> unoptimized(function->shared()->code());
6839 // Keep track of whether we've succeeded in optimizing.
6840 bool succeeded = unoptimized->optimizable();
6841 if (succeeded) {
6842 // If we are trying to do OSR when there are already optimized
6843 // activations of the function, it means (a) the function is directly or
6844 // indirectly recursive and (b) an optimized invocation has been
6845 // deoptimized so that we are currently in an unoptimized activation.
6846 // Check for optimized activations of this function.
6847 JavaScriptFrameIterator it;
6848 while (succeeded && !it.done()) {
6849 JavaScriptFrame* frame = it.frame();
6850 succeeded = !frame->is_optimized() || frame->function() != *function;
6851 it.Advance();
6852 }
6853 }
6854
6855 int ast_id = AstNode::kNoNumber;
6856 if (succeeded) {
6857 // The top JS function is this one, the PC is somewhere in the
6858 // unoptimized code.
6859 JavaScriptFrameIterator it;
6860 JavaScriptFrame* frame = it.frame();
6861 ASSERT(frame->function() == *function);
6862 ASSERT(frame->code() == *unoptimized);
6863 ASSERT(unoptimized->contains(frame->pc()));
6864
6865 // Use linear search of the unoptimized code's stack check table to find
6866 // the AST id matching the PC.
6867 Address start = unoptimized->instruction_start();
6868 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
6869 Address table_cursor = start + unoptimized->stack_check_table_start();
6870 uint32_t table_length = Memory::uint32_at(table_cursor);
6871 table_cursor += kIntSize;
6872 for (unsigned i = 0; i < table_length; ++i) {
6873 // Table entries are (AST id, pc offset) pairs.
6874 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
6875 if (pc_offset == target_pc_offset) {
6876 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
6877 break;
6878 }
6879 table_cursor += 2 * kIntSize;
6880 }
6881 ASSERT(ast_id != AstNode::kNoNumber);
6882 if (FLAG_trace_osr) {
6883 PrintF("[replacing on-stack at AST id %d in ", ast_id);
6884 function->PrintName();
6885 PrintF("]\n");
6886 }
6887
6888 // Try to compile the optimized code. A true return value from
6889 // CompileOptimized means that compilation succeeded, not necessarily
6890 // that optimization succeeded.
6891 if (CompileOptimized(function, ast_id) && function->IsOptimized()) {
6892 DeoptimizationInputData* data = DeoptimizationInputData::cast(
6893 function->code()->deoptimization_data());
6894 if (FLAG_trace_osr) {
6895 PrintF("[on-stack replacement offset %d in optimized code]\n",
6896 data->OsrPcOffset()->value());
6897 }
6898 ASSERT(data->OsrAstId()->value() == ast_id);
6899 ASSERT(data->OsrPcOffset()->value() >= 0);
6900 } else {
6901 succeeded = false;
6902 }
6903 }
6904
6905 // Revert to the original stack checks in the original unoptimized code.
6906 if (FLAG_trace_osr) {
6907 PrintF("[restoring original stack checks in ");
6908 function->PrintName();
6909 PrintF("]\n");
6910 }
6911 StackCheckStub check_stub;
6912 Handle<Code> check_code = check_stub.GetCode();
6913 Handle<Code> replacement_code(
6914 Builtins::builtin(Builtins::OnStackReplacement));
6915 // Iterate the unoptimized code and revert all the patched stack checks.
6916 for (RelocIterator it(*unoptimized, RelocInfo::kCodeTargetMask);
6917 !it.done();
6918 it.next()) {
6919 RelocInfo* rinfo = it.rinfo();
6920 if (rinfo->target_address() == replacement_code->entry()) {
6921 Deoptimizer::RevertStackCheckCode(rinfo, *check_code);
6922 }
6923 }
6924
6925 // Allow OSR only at nesting level zero again.
6926 unoptimized->set_allow_osr_at_loop_nesting_level(0);
6927
6928 // If the optimization attempt succeeded, return the AST id tagged as a
6929 // smi. This tells the builtin that we need to translate the unoptimized
6930 // frame to an optimized one.
6931 if (succeeded) {
6932 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
6933 return Smi::FromInt(ast_id);
6934 } else {
6935 return Smi::FromInt(-1);
6936 }
6937}
6938
6939
lrn@chromium.org303ada72010-10-27 09:33:13 +00006940static MaybeObject* Runtime_GetFunctionDelegate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006941 HandleScope scope;
6942 ASSERT(args.length() == 1);
6943 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6944 return *Execution::GetFunctionDelegate(args.at<Object>(0));
6945}
6946
6947
lrn@chromium.org303ada72010-10-27 09:33:13 +00006948static MaybeObject* Runtime_GetConstructorDelegate(Arguments args) {
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00006949 HandleScope scope;
6950 ASSERT(args.length() == 1);
6951 RUNTIME_ASSERT(!args[0]->IsJSFunction());
6952 return *Execution::GetConstructorDelegate(args.at<Object>(0));
6953}
6954
6955
lrn@chromium.org303ada72010-10-27 09:33:13 +00006956static MaybeObject* Runtime_NewContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006957 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00006958 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006959
kasper.lund7276f142008-07-30 08:49:36 +00006960 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00006961 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00006962 Object* result;
6963 { MaybeObject* maybe_result = Heap::AllocateFunctionContext(length, function);
6964 if (!maybe_result->ToObject(&result)) return maybe_result;
6965 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006966
6967 Top::set_context(Context::cast(result));
6968
kasper.lund7276f142008-07-30 08:49:36 +00006969 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006970}
6971
lrn@chromium.org303ada72010-10-27 09:33:13 +00006972
6973MUST_USE_RESULT static MaybeObject* PushContextHelper(Object* object,
6974 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006975 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006976 Object* js_object = object;
6977 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006978 MaybeObject* maybe_js_object = js_object->ToObject();
6979 if (!maybe_js_object->ToObject(&js_object)) {
6980 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
6981 return maybe_js_object;
6982 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006983 HandleScope scope;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006984 Handle<Object> handle(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006985 Handle<Object> result =
6986 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
6987 return Top::Throw(*result);
6988 }
6989 }
6990
lrn@chromium.org303ada72010-10-27 09:33:13 +00006991 Object* result;
6992 { MaybeObject* maybe_result =
6993 Heap::AllocateWithContext(Top::context(),
6994 JSObject::cast(js_object),
6995 is_catch_context);
6996 if (!maybe_result->ToObject(&result)) return maybe_result;
6997 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006998
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00006999 Context* context = Context::cast(result);
7000 Top::set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007001
kasper.lund7276f142008-07-30 08:49:36 +00007002 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007003}
7004
7005
lrn@chromium.org303ada72010-10-27 09:33:13 +00007006static MaybeObject* Runtime_PushContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007007 NoHandleAllocation ha;
7008 ASSERT(args.length() == 1);
7009 return PushContextHelper(args[0], false);
7010}
7011
7012
lrn@chromium.org303ada72010-10-27 09:33:13 +00007013static MaybeObject* Runtime_PushCatchContext(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007014 NoHandleAllocation ha;
7015 ASSERT(args.length() == 1);
7016 return PushContextHelper(args[0], true);
7017}
7018
7019
lrn@chromium.org303ada72010-10-27 09:33:13 +00007020static MaybeObject* Runtime_LookupContext(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007021 HandleScope scope;
7022 ASSERT(args.length() == 2);
7023
7024 CONVERT_ARG_CHECKED(Context, context, 0);
7025 CONVERT_ARG_CHECKED(String, name, 1);
7026
7027 int index;
7028 PropertyAttributes attributes;
7029 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007030 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007031 context->Lookup(name, flags, &index, &attributes);
7032
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007033 if (index < 0 && !holder.is_null()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007034 ASSERT(holder->IsJSObject());
7035 return *holder;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007036 }
7037
7038 // No intermediate context found. Use global object by default.
7039 return Top::context()->global();
7040}
7041
7042
ager@chromium.orga1645e22009-09-09 19:27:10 +00007043// A mechanism to return a pair of Object pointers in registers (if possible).
7044// How this is achieved is calling convention-dependent.
7045// All currently supported x86 compiles uses calling conventions that are cdecl
7046// variants where a 64-bit value is returned in two 32-bit registers
7047// (edx:eax on ia32, r1:r0 on ARM).
7048// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7049// In Win64 calling convention, a struct of two pointers is returned in memory,
7050// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007051#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007052struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007053 MaybeObject* x;
7054 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007055};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007056
lrn@chromium.org303ada72010-10-27 09:33:13 +00007057static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007058 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007059 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7060 // In Win64 they are assigned to a hidden first argument.
7061 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007062}
7063#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007064typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007065static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007066 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007067 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007068}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007069#endif
7070
7071
lrn@chromium.org303ada72010-10-27 09:33:13 +00007072static inline MaybeObject* Unhole(MaybeObject* x,
7073 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007074 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7075 USE(attributes);
7076 return x->IsTheHole() ? Heap::undefined_value() : x;
7077}
7078
7079
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007080static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
7081 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007082 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007083 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007084 JSFunction* context_extension_function =
7085 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007086 // If the holder isn't a context extension object, we just return it
7087 // as the receiver. This allows arguments objects to be used as
7088 // receivers, but only if they are put in the context scope chain
7089 // explicitly via a with-statement.
7090 Object* constructor = holder->map()->constructor();
7091 if (constructor != context_extension_function) return holder;
7092 // Fall back to using the global object as the receiver if the
7093 // property turns out to be a local variable allocated in a context
7094 // extension object - introduced via eval.
7095 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007096}
7097
7098
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007099static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007100 HandleScope scope;
ager@chromium.orga1645e22009-09-09 19:27:10 +00007101 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007102
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007103 if (!args[0]->IsContext() || !args[1]->IsString()) {
ager@chromium.org3e875802009-06-29 08:26:34 +00007104 return MakePair(Top::ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007105 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007106 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007107 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007108
7109 int index;
7110 PropertyAttributes attributes;
7111 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007112 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007113 context->Lookup(name, flags, &index, &attributes);
7114
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007115 // If the index is non-negative, the slot has been found in a local
7116 // variable or a parameter. Read it from the context object or the
7117 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007118 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007119 // If the "property" we were looking for is a local variable or an
7120 // argument in a context, the receiver is the global object; see
7121 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
7122 JSObject* receiver = Top::context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007123 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007124 ? Context::cast(*holder)->get(index)
7125 : JSObject::cast(*holder)->GetElement(index);
7126 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007127 }
7128
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007129 // If the holder is found, we read the property from it.
7130 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007131 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007132 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007133 JSObject* receiver;
7134 if (object->IsGlobalObject()) {
7135 receiver = GlobalObject::cast(object)->global_receiver();
7136 } else if (context->is_exception_holder(*holder)) {
7137 receiver = Top::context()->global()->global_receiver();
7138 } else {
7139 receiver = ComputeReceiverForNonGlobal(object);
7140 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007141 // No need to unhole the value here. This is taken care of by the
7142 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007143 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007144 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007145 }
7146
7147 if (throw_error) {
7148 // The property doesn't exist - throw exception.
7149 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007150 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007151 return MakePair(Top::Throw(*reference_error), NULL);
7152 } else {
7153 // The property doesn't exist - return undefined
7154 return MakePair(Heap::undefined_value(), Heap::undefined_value());
7155 }
7156}
7157
7158
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007159static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007160 return LoadContextSlotHelper(args, true);
7161}
7162
7163
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007164static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007165 return LoadContextSlotHelper(args, false);
7166}
7167
7168
lrn@chromium.org303ada72010-10-27 09:33:13 +00007169static MaybeObject* Runtime_StoreContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007170 HandleScope scope;
7171 ASSERT(args.length() == 3);
7172
7173 Handle<Object> value(args[0]);
7174 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007175 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007176
7177 int index;
7178 PropertyAttributes attributes;
7179 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007180 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007181 context->Lookup(name, flags, &index, &attributes);
7182
7183 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007184 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007185 // Ignore if read_only variable.
7186 if ((attributes & READ_ONLY) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007187 Handle<Context>::cast(holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007188 }
7189 } else {
7190 ASSERT((attributes & READ_ONLY) == 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007191 Handle<JSObject>::cast(holder)->SetElement(index, *value)->
7192 ToObjectUnchecked();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007193 }
7194 return *value;
7195 }
7196
7197 // Slow case: The property is not in a FixedArray context.
7198 // It is either in an JSObject extension context or it was not found.
7199 Handle<JSObject> context_ext;
7200
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007201 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007202 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007203 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007204 } else {
7205 // The property was not found. It needs to be stored in the global context.
7206 ASSERT(attributes == ABSENT);
7207 attributes = NONE;
7208 context_ext = Handle<JSObject>(Top::context()->global());
7209 }
7210
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007211 // Set the property, but ignore if read_only variable on the context
7212 // extension object itself.
7213 if ((attributes & READ_ONLY) == 0 ||
7214 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007215 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
7216 if (set.is_null()) {
7217 // Failure::Exception is converted to a null handle in the
7218 // handle-based methods such as SetProperty. We therefore need
7219 // to convert null handles back to exceptions.
7220 ASSERT(Top::has_pending_exception());
7221 return Failure::Exception();
7222 }
7223 }
7224 return *value;
7225}
7226
7227
lrn@chromium.org303ada72010-10-27 09:33:13 +00007228static MaybeObject* Runtime_Throw(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007229 HandleScope scope;
7230 ASSERT(args.length() == 1);
7231
7232 return Top::Throw(args[0]);
7233}
7234
7235
lrn@chromium.org303ada72010-10-27 09:33:13 +00007236static MaybeObject* Runtime_ReThrow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007237 HandleScope scope;
7238 ASSERT(args.length() == 1);
7239
7240 return Top::ReThrow(args[0]);
7241}
7242
7243
lrn@chromium.org303ada72010-10-27 09:33:13 +00007244static MaybeObject* Runtime_PromoteScheduledException(Arguments args) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007245 ASSERT_EQ(0, args.length());
7246 return Top::PromoteScheduledException();
7247}
7248
7249
lrn@chromium.org303ada72010-10-27 09:33:13 +00007250static MaybeObject* Runtime_ThrowReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007251 HandleScope scope;
7252 ASSERT(args.length() == 1);
7253
7254 Handle<Object> name(args[0]);
7255 Handle<Object> reference_error =
7256 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
7257 return Top::Throw(*reference_error);
7258}
7259
7260
lrn@chromium.org303ada72010-10-27 09:33:13 +00007261static MaybeObject* Runtime_StackOverflow(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007262 NoHandleAllocation na;
7263 return Top::StackOverflow();
7264}
7265
7266
lrn@chromium.org303ada72010-10-27 09:33:13 +00007267static MaybeObject* Runtime_StackGuard(Arguments args) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007268 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007269
7270 // First check if this is a real stack overflow.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007271 if (StackGuard::IsStackOverflow()) {
7272 return Runtime_StackOverflow(args);
7273 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007274
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007275 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007276}
7277
7278
7279// NOTE: These PrintXXX functions are defined for all builds (not just
7280// DEBUG builds) because we may want to be able to trace function
7281// calls in all modes.
7282static void PrintString(String* str) {
7283 // not uncommon to have empty strings
7284 if (str->length() > 0) {
7285 SmartPointer<char> s =
7286 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
7287 PrintF("%s", *s);
7288 }
7289}
7290
7291
7292static void PrintObject(Object* obj) {
7293 if (obj->IsSmi()) {
7294 PrintF("%d", Smi::cast(obj)->value());
7295 } else if (obj->IsString() || obj->IsSymbol()) {
7296 PrintString(String::cast(obj));
7297 } else if (obj->IsNumber()) {
7298 PrintF("%g", obj->Number());
7299 } else if (obj->IsFailure()) {
7300 PrintF("<failure>");
7301 } else if (obj->IsUndefined()) {
7302 PrintF("<undefined>");
7303 } else if (obj->IsNull()) {
7304 PrintF("<null>");
7305 } else if (obj->IsTrue()) {
7306 PrintF("<true>");
7307 } else if (obj->IsFalse()) {
7308 PrintF("<false>");
7309 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007310 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007311 }
7312}
7313
7314
7315static int StackSize() {
7316 int n = 0;
7317 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
7318 return n;
7319}
7320
7321
7322static void PrintTransition(Object* result) {
7323 // indentation
7324 { const int nmax = 80;
7325 int n = StackSize();
7326 if (n <= nmax)
7327 PrintF("%4d:%*s", n, n, "");
7328 else
7329 PrintF("%4d:%*s", n, nmax, "...");
7330 }
7331
7332 if (result == NULL) {
7333 // constructor calls
7334 JavaScriptFrameIterator it;
7335 JavaScriptFrame* frame = it.frame();
7336 if (frame->IsConstructor()) PrintF("new ");
7337 // function name
7338 Object* fun = frame->function();
7339 if (fun->IsJSFunction()) {
7340 PrintObject(JSFunction::cast(fun)->shared()->name());
7341 } else {
7342 PrintObject(fun);
7343 }
7344 // function arguments
7345 // (we are intentionally only printing the actually
7346 // supplied parameters, not all parameters required)
7347 PrintF("(this=");
7348 PrintObject(frame->receiver());
7349 const int length = frame->GetProvidedParametersCount();
7350 for (int i = 0; i < length; i++) {
7351 PrintF(", ");
7352 PrintObject(frame->GetParameter(i));
7353 }
7354 PrintF(") {\n");
7355
7356 } else {
7357 // function result
7358 PrintF("} -> ");
7359 PrintObject(result);
7360 PrintF("\n");
7361 }
7362}
7363
7364
lrn@chromium.org303ada72010-10-27 09:33:13 +00007365static MaybeObject* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007366 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007367 NoHandleAllocation ha;
7368 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007369 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007370}
7371
7372
lrn@chromium.org303ada72010-10-27 09:33:13 +00007373static MaybeObject* Runtime_TraceExit(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007374 NoHandleAllocation ha;
7375 PrintTransition(args[0]);
7376 return args[0]; // return TOS
7377}
7378
7379
lrn@chromium.org303ada72010-10-27 09:33:13 +00007380static MaybeObject* Runtime_DebugPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007381 NoHandleAllocation ha;
7382 ASSERT(args.length() == 1);
7383
7384#ifdef DEBUG
7385 if (args[0]->IsString()) {
7386 // If we have a string, assume it's a code "marker"
7387 // and print some interesting cpu debugging info.
7388 JavaScriptFrameIterator it;
7389 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007390 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
7391 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007392 } else {
7393 PrintF("DebugPrint: ");
7394 }
7395 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007396 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007397 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007398 HeapObject::cast(args[0])->map()->Print();
7399 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007400#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007401 // ShortPrint is available in release mode. Print is not.
7402 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007403#endif
7404 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00007405 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007406
7407 return args[0]; // return TOS
7408}
7409
7410
lrn@chromium.org303ada72010-10-27 09:33:13 +00007411static MaybeObject* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007412 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007413 NoHandleAllocation ha;
7414 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007415 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007416}
7417
7418
lrn@chromium.org303ada72010-10-27 09:33:13 +00007419static MaybeObject* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007420 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007421 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007422
7423 // According to ECMA-262, section 15.9.1, page 117, the precision of
7424 // the number in a Date object representing a particular instant in
7425 // time is milliseconds. Therefore, we floor the result of getting
7426 // the OS time.
7427 double millis = floor(OS::TimeCurrentMillis());
7428 return Heap::NumberFromDouble(millis);
7429}
7430
7431
lrn@chromium.org303ada72010-10-27 09:33:13 +00007432static MaybeObject* Runtime_DateParseString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007433 HandleScope scope;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007434 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007435
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007436 CONVERT_ARG_CHECKED(String, str, 0);
7437 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007438
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007439 CONVERT_ARG_CHECKED(JSArray, output, 1);
7440 RUNTIME_ASSERT(output->HasFastElements());
7441
7442 AssertNoAllocation no_allocation;
7443
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007444 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007445 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
7446 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00007447 if (str->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007448 result = DateParser::Parse(str->ToAsciiVector(), output_array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007449 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00007450 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007451 result = DateParser::Parse(str->ToUC16Vector(), output_array);
7452 }
7453
7454 if (result) {
7455 return *output;
7456 } else {
7457 return Heap::null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007458 }
7459}
7460
7461
lrn@chromium.org303ada72010-10-27 09:33:13 +00007462static MaybeObject* Runtime_DateLocalTimezone(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007463 NoHandleAllocation ha;
7464 ASSERT(args.length() == 1);
7465
7466 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00007467 const char* zone = OS::LocalTimezone(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007468 return Heap::AllocateStringFromUtf8(CStrVector(zone));
7469}
7470
7471
lrn@chromium.org303ada72010-10-27 09:33:13 +00007472static MaybeObject* Runtime_DateLocalTimeOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007473 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00007474 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007475
7476 return Heap::NumberFromDouble(OS::LocalTimeOffset());
7477}
7478
7479
lrn@chromium.org303ada72010-10-27 09:33:13 +00007480static MaybeObject* Runtime_DateDaylightSavingsOffset(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007481 NoHandleAllocation ha;
7482 ASSERT(args.length() == 1);
7483
7484 CONVERT_DOUBLE_CHECKED(x, args[0]);
7485 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
7486}
7487
7488
lrn@chromium.org303ada72010-10-27 09:33:13 +00007489static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007490 ASSERT(args.length() == 1);
7491 Object* global = args[0];
7492 if (!global->IsJSGlobalObject()) return Heap::null_value();
7493 return JSGlobalObject::cast(global)->global_receiver();
7494}
7495
7496
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007497static MaybeObject* Runtime_ParseJson(Arguments args) {
7498 HandleScope scope;
7499 ASSERT_EQ(1, args.length());
7500 CONVERT_ARG_CHECKED(String, source, 0);
7501
7502 Handle<Object> result = JsonParser::Parse(source);
7503 if (result.is_null()) {
7504 // Syntax error or stack overflow in scanner.
7505 ASSERT(Top::has_pending_exception());
7506 return Failure::Exception();
7507 }
7508 return *result;
7509}
7510
7511
lrn@chromium.org303ada72010-10-27 09:33:13 +00007512static MaybeObject* Runtime_CompileString(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007513 HandleScope scope;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007514 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007515 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007516
ager@chromium.org381abbb2009-02-25 13:23:22 +00007517 // Compile source string in the global context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007518 Handle<Context> context(Top::context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007519 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
7520 context,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007521 true);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007522 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007523 Handle<JSFunction> fun =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007524 Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007525 return *fun;
7526}
7527
7528
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007529static ObjectPair CompileGlobalEval(Handle<String> source,
7530 Handle<Object> receiver) {
7531 // Deal with a normal eval call with a string argument. Compile it
7532 // and return the compiled function bound in the local context.
7533 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
7534 source,
7535 Handle<Context>(Top::context()),
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00007536 Top::context()->IsGlobalContext());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007537 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
7538 Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
7539 shared,
7540 Handle<Context>(Top::context()),
7541 NOT_TENURED);
7542 return MakePair(*compiled, *receiver);
7543}
7544
7545
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007546static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
7547 ASSERT(args.length() == 3);
7548 if (!args[0]->IsJSFunction()) {
7549 return MakePair(Top::ThrowIllegalOperation(), NULL);
7550 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007551
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007552 HandleScope scope;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007553 Handle<JSFunction> callee = args.at<JSFunction>(0);
7554 Handle<Object> receiver; // Will be overwritten.
7555
7556 // Compute the calling context.
7557 Handle<Context> context = Handle<Context>(Top::context());
7558#ifdef DEBUG
7559 // Make sure Top::context() agrees with the old code that traversed
7560 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007561 StackFrameLocator locator;
7562 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007563 ASSERT(Context::cast(frame->context()) == *context);
7564#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007565
7566 // Find where the 'eval' symbol is bound. It is unaliased only if
7567 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007568 int index = -1;
7569 PropertyAttributes attributes = ABSENT;
7570 while (true) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007571 receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
7572 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007573 // Stop search when eval is found or when the global context is
7574 // reached.
7575 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007576 if (context->is_function_context()) {
7577 context = Handle<Context>(Context::cast(context->closure()->context()));
7578 } else {
7579 context = Handle<Context>(context->previous());
7580 }
7581 }
7582
iposva@chromium.org245aa852009-02-10 00:49:54 +00007583 // If eval could not be resolved, it has been deleted and we need to
7584 // throw a reference error.
7585 if (attributes == ABSENT) {
7586 Handle<Object> name = Factory::eval_symbol();
7587 Handle<Object> reference_error =
7588 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007589 return MakePair(Top::Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00007590 }
7591
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007592 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007593 // 'eval' is not bound in the global context. Just call the function
7594 // with the given arguments. This is not necessarily the global eval.
7595 if (receiver->IsContext()) {
7596 context = Handle<Context>::cast(receiver);
7597 receiver = Handle<Object>(context->get(index));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007598 } else if (receiver->IsJSContextExtensionObject()) {
7599 receiver = Handle<JSObject>(Top::context()->global()->global_receiver());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007600 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007601 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007602 }
7603
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007604 // 'eval' is bound in the global context, but it may have been overwritten.
7605 // Compare it to the builtin 'GlobalEval' function to make sure.
7606 if (*callee != Top::global_context()->global_eval_fun() ||
7607 !args[1]->IsString()) {
7608 return MakePair(*callee, Top::context()->global()->global_receiver());
7609 }
7610
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007611 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
7612}
7613
7614
7615static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
7616 ASSERT(args.length() == 3);
7617 if (!args[0]->IsJSFunction()) {
7618 return MakePair(Top::ThrowIllegalOperation(), NULL);
7619 }
7620
7621 HandleScope scope;
7622 Handle<JSFunction> callee = args.at<JSFunction>(0);
7623
7624 // 'eval' is bound in the global context, but it may have been overwritten.
7625 // Compare it to the builtin 'GlobalEval' function to make sure.
7626 if (*callee != Top::global_context()->global_eval_fun() ||
7627 !args[1]->IsString()) {
7628 return MakePair(*callee, Top::context()->global()->global_receiver());
7629 }
7630
7631 return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007632}
7633
7634
lrn@chromium.org303ada72010-10-27 09:33:13 +00007635static MaybeObject* Runtime_SetNewFunctionAttributes(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007636 // This utility adjusts the property attributes for newly created Function
7637 // object ("new Function(...)") by changing the map.
7638 // All it does is changing the prototype property to enumerable
7639 // as specified in ECMA262, 15.3.5.2.
7640 HandleScope scope;
7641 ASSERT(args.length() == 1);
7642 CONVERT_ARG_CHECKED(JSFunction, func, 0);
7643 ASSERT(func->map()->instance_type() ==
7644 Top::function_instance_map()->instance_type());
7645 ASSERT(func->map()->instance_size() ==
7646 Top::function_instance_map()->instance_size());
7647 func->set_map(*Top::function_instance_map());
7648 return *func;
7649}
7650
7651
lrn@chromium.org303ada72010-10-27 09:33:13 +00007652static MaybeObject* Runtime_AllocateInNewSpace(Arguments args) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007653 // Allocate a block of memory in NewSpace (filled with a filler).
7654 // Use as fallback for allocation in generated code when NewSpace
7655 // is full.
7656 ASSERT(args.length() == 1);
7657 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
7658 int size = size_smi->value();
7659 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
7660 RUNTIME_ASSERT(size > 0);
7661 static const int kMinFreeNewSpaceAfterGC =
7662 Heap::InitialSemiSpaceSize() * 3/4;
7663 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007664 Object* allocation;
7665 { MaybeObject* maybe_allocation = Heap::new_space()->AllocateRaw(size);
7666 if (maybe_allocation->ToObject(&allocation)) {
7667 Heap::CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
7668 }
7669 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007670 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00007671}
7672
7673
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007674// Push an array unto an array of arrays if it is not already in the
7675// array. Returns true if the element was pushed on the stack and
7676// false otherwise.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007677static MaybeObject* Runtime_PushIfAbsent(Arguments args) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007678 ASSERT(args.length() == 2);
7679 CONVERT_CHECKED(JSArray, array, args[0]);
7680 CONVERT_CHECKED(JSArray, element, args[1]);
7681 RUNTIME_ASSERT(array->HasFastElements());
7682 int length = Smi::cast(array->length())->value();
7683 FixedArray* elements = FixedArray::cast(array->elements());
7684 for (int i = 0; i < length; i++) {
7685 if (elements->get(i) == element) return Heap::false_value();
7686 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007687 Object* obj;
7688 { MaybeObject* maybe_obj = array->SetFastElement(length, element);
7689 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7690 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007691 return Heap::true_value();
7692}
7693
7694
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007695/**
7696 * A simple visitor visits every element of Array's.
7697 * The backend storage can be a fixed array for fast elements case,
7698 * or a dictionary for sparse array. Since Dictionary is a subtype
7699 * of FixedArray, the class can be used by both fast and slow cases.
7700 * The second parameter of the constructor, fast_elements, specifies
7701 * whether the storage is a FixedArray or Dictionary.
7702 *
7703 * An index limit is used to deal with the situation that a result array
7704 * length overflows 32-bit non-negative integer.
7705 */
7706class ArrayConcatVisitor {
7707 public:
7708 ArrayConcatVisitor(Handle<FixedArray> storage,
7709 uint32_t index_limit,
7710 bool fast_elements) :
7711 storage_(storage), index_limit_(index_limit),
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007712 index_offset_(0), fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007713
7714 void visit(uint32_t i, Handle<Object> elm) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007715 if (i >= index_limit_ - index_offset_) return;
7716 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007717
7718 if (fast_elements_) {
7719 ASSERT(index < static_cast<uint32_t>(storage_->length()));
7720 storage_->set(index, *elm);
7721
7722 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00007723 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_);
7724 Handle<NumberDictionary> result =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007725 Factory::DictionaryAtNumberPut(dict, index, elm);
7726 if (!result.is_identical_to(dict))
7727 storage_ = result;
7728 }
7729 }
7730
7731 void increase_index_offset(uint32_t delta) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007732 if (index_limit_ - index_offset_ < delta) {
7733 index_offset_ = index_limit_;
7734 } else {
7735 index_offset_ += delta;
7736 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007737 }
7738
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00007739 Handle<FixedArray> storage() { return storage_; }
7740
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007741 private:
7742 Handle<FixedArray> storage_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007743 // Limit on the accepted indices. Elements with indices larger than the
7744 // limit are ignored by the visitor.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007745 uint32_t index_limit_;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007746 // Index after last seen index. Always less than or equal to index_limit_.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007747 uint32_t index_offset_;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007748 const bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007749};
7750
7751
ager@chromium.org3811b432009-10-28 14:53:37 +00007752template<class ExternalArrayClass, class ElementType>
7753static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver,
7754 bool elements_are_ints,
7755 bool elements_are_guaranteed_smis,
7756 uint32_t range,
7757 ArrayConcatVisitor* visitor) {
7758 Handle<ExternalArrayClass> array(
7759 ExternalArrayClass::cast(receiver->elements()));
7760 uint32_t len = Min(static_cast<uint32_t>(array->length()), range);
7761
7762 if (visitor != NULL) {
7763 if (elements_are_ints) {
7764 if (elements_are_guaranteed_smis) {
7765 for (uint32_t j = 0; j < len; j++) {
7766 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
7767 visitor->visit(j, e);
7768 }
7769 } else {
7770 for (uint32_t j = 0; j < len; j++) {
7771 int64_t val = static_cast<int64_t>(array->get(j));
7772 if (Smi::IsValid(static_cast<intptr_t>(val))) {
7773 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
7774 visitor->visit(j, e);
7775 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007776 Handle<Object> e =
7777 Factory::NewNumber(static_cast<ElementType>(val));
ager@chromium.org3811b432009-10-28 14:53:37 +00007778 visitor->visit(j, e);
7779 }
7780 }
7781 }
7782 } else {
7783 for (uint32_t j = 0; j < len; j++) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007784 Handle<Object> e = Factory::NewNumber(array->get(j));
ager@chromium.org3811b432009-10-28 14:53:37 +00007785 visitor->visit(j, e);
7786 }
7787 }
7788 }
7789
7790 return len;
7791}
7792
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007793/**
7794 * A helper function that visits elements of a JSObject. Only elements
7795 * whose index between 0 and range (exclusive) are visited.
7796 *
7797 * If the third parameter, visitor, is not NULL, the visitor is called
7798 * with parameters, 'visitor_index_offset + element index' and the element.
7799 *
7800 * It returns the number of visisted elements.
7801 */
7802static uint32_t IterateElements(Handle<JSObject> receiver,
7803 uint32_t range,
7804 ArrayConcatVisitor* visitor) {
7805 uint32_t num_of_elements = 0;
7806
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007807 switch (receiver->GetElementsKind()) {
7808 case JSObject::FAST_ELEMENTS: {
7809 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
7810 uint32_t len = elements->length();
7811 if (range < len) {
7812 len = range;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007813 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007814
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007815 for (uint32_t j = 0; j < len; j++) {
7816 Handle<Object> e(elements->get(j));
7817 if (!e->IsTheHole()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007818 num_of_elements++;
7819 if (visitor) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007820 visitor->visit(j, e);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007821 }
7822 }
7823 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007824 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007825 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007826 case JSObject::PIXEL_ELEMENTS: {
7827 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
7828 uint32_t len = pixels->length();
7829 if (range < len) {
7830 len = range;
7831 }
7832
7833 for (uint32_t j = 0; j < len; j++) {
7834 num_of_elements++;
7835 if (visitor != NULL) {
7836 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
7837 visitor->visit(j, e);
7838 }
7839 }
7840 break;
7841 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007842 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
7843 num_of_elements =
7844 IterateExternalArrayElements<ExternalByteArray, int8_t>(
7845 receiver, true, true, range, visitor);
7846 break;
7847 }
7848 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
7849 num_of_elements =
7850 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
7851 receiver, true, true, range, visitor);
7852 break;
7853 }
7854 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
7855 num_of_elements =
7856 IterateExternalArrayElements<ExternalShortArray, int16_t>(
7857 receiver, true, true, range, visitor);
7858 break;
7859 }
7860 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
7861 num_of_elements =
7862 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
7863 receiver, true, true, range, visitor);
7864 break;
7865 }
7866 case JSObject::EXTERNAL_INT_ELEMENTS: {
7867 num_of_elements =
7868 IterateExternalArrayElements<ExternalIntArray, int32_t>(
7869 receiver, true, false, range, visitor);
7870 break;
7871 }
7872 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
7873 num_of_elements =
7874 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
7875 receiver, true, false, range, visitor);
7876 break;
7877 }
7878 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
7879 num_of_elements =
7880 IterateExternalArrayElements<ExternalFloatArray, float>(
7881 receiver, false, false, range, visitor);
7882 break;
7883 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007884 case JSObject::DICTIONARY_ELEMENTS: {
7885 Handle<NumberDictionary> dict(receiver->element_dictionary());
7886 uint32_t capacity = dict->Capacity();
7887 for (uint32_t j = 0; j < capacity; j++) {
7888 Handle<Object> k(dict->KeyAt(j));
7889 if (dict->IsKey(*k)) {
7890 ASSERT(k->IsNumber());
7891 uint32_t index = static_cast<uint32_t>(k->Number());
7892 if (index < range) {
7893 num_of_elements++;
7894 if (visitor) {
7895 visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
7896 }
7897 }
7898 }
7899 }
7900 break;
7901 }
7902 default:
7903 UNREACHABLE();
7904 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007905 }
7906
7907 return num_of_elements;
7908}
7909
7910
7911/**
7912 * A helper function that visits elements of an Array object, and elements
7913 * on its prototypes.
7914 *
7915 * Elements on prototypes are visited first, and only elements whose indices
7916 * less than Array length are visited.
7917 *
7918 * If a ArrayConcatVisitor object is given, the visitor is called with
7919 * parameters, element's index + visitor_index_offset and the element.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007920 *
7921 * The returned number of elements is an upper bound on the actual number
7922 * of elements added. If the same element occurs in more than one object
7923 * in the array's prototype chain, it will be counted more than once, but
7924 * will only occur once in the result.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007925 */
7926static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
7927 ArrayConcatVisitor* visitor) {
7928 uint32_t range = static_cast<uint32_t>(array->length()->Number());
7929 Handle<Object> obj = array;
7930
7931 static const int kEstimatedPrototypes = 3;
7932 List< Handle<JSObject> > objects(kEstimatedPrototypes);
7933
7934 // Visit prototype first. If an element on the prototype is shadowed by
7935 // the inheritor using the same index, the ArrayConcatVisitor visits
7936 // the prototype element before the shadowing element.
7937 // The visitor can simply overwrite the old value by new value using
7938 // the same index. This follows Array::concat semantics.
7939 while (!obj->IsNull()) {
7940 objects.Add(Handle<JSObject>::cast(obj));
7941 obj = Handle<Object>(obj->GetPrototype());
7942 }
7943
7944 uint32_t nof_elements = 0;
7945 for (int i = objects.length() - 1; i >= 0; i--) {
7946 Handle<JSObject> obj = objects[i];
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007947 uint32_t encountered_elements =
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007948 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007949
7950 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
7951 nof_elements = JSObject::kMaxElementCount;
7952 } else {
7953 nof_elements += encountered_elements;
7954 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007955 }
7956
7957 return nof_elements;
7958}
7959
7960
7961/**
7962 * A helper function of Runtime_ArrayConcat.
7963 *
7964 * The first argument is an Array of arrays and objects. It is the
7965 * same as the arguments array of Array::concat JS function.
7966 *
7967 * If an argument is an Array object, the function visits array
7968 * elements. If an argument is not an Array object, the function
7969 * visits the object as if it is an one-element array.
7970 *
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007971 * If the result array index overflows 32-bit unsigned integer, the rounded
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007972 * non-negative number is used as new length. For example, if one
7973 * array length is 2^32 - 1, second array length is 1, the
7974 * concatenated array length is 0.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007975 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
7976 * is one more than the last array index to get a value assigned).
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007977 */
7978static uint32_t IterateArguments(Handle<JSArray> arguments,
7979 ArrayConcatVisitor* visitor) {
7980 uint32_t visited_elements = 0;
7981 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
7982
7983 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007984 Object *element;
7985 MaybeObject* maybe_element = arguments->GetElement(i);
7986 // This if() is not expected to fail, but we have the check in the
7987 // interest of hardening the runtime calls.
7988 if (maybe_element->ToObject(&element)) {
7989 Handle<Object> obj(element);
7990 if (obj->IsJSArray()) {
7991 Handle<JSArray> array = Handle<JSArray>::cast(obj);
7992 uint32_t len = static_cast<uint32_t>(array->length()->Number());
7993 uint32_t nof_elements =
7994 IterateArrayAndPrototypeElements(array, visitor);
7995 // Total elements of array and its prototype chain can be more than
7996 // the array length, but ArrayConcat can only concatenate at most
7997 // the array length number of elements. We use the length as an estimate
7998 // for the actual number of elements added.
7999 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
8000 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
8001 visited_elements = JSArray::kMaxElementCount;
8002 } else {
8003 visited_elements += added_elements;
8004 }
8005 if (visitor) visitor->increase_index_offset(len);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008006 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008007 if (visitor) {
8008 visitor->visit(0, obj);
8009 visitor->increase_index_offset(1);
8010 }
8011 if (visited_elements < JSArray::kMaxElementCount) {
8012 visited_elements++;
8013 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008014 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008015 }
8016 }
8017 return visited_elements;
8018}
8019
8020
8021/**
8022 * Array::concat implementation.
8023 * See ECMAScript 262, 15.4.4.4.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008024 * TODO(lrn): Fix non-compliance for very large concatenations and update to
8025 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008026 */
lrn@chromium.org303ada72010-10-27 09:33:13 +00008027static MaybeObject* Runtime_ArrayConcat(Arguments args) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008028 ASSERT(args.length() == 1);
8029 HandleScope handle_scope;
8030
8031 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
8032 Handle<JSArray> arguments(arg_arrays);
8033
8034 // Pass 1: estimate the number of elements of the result
8035 // (it could be more than real numbers if prototype has elements).
8036 uint32_t result_length = 0;
8037 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
8038
8039 { AssertNoAllocation nogc;
8040 for (uint32_t i = 0; i < num_of_args; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008041 Object* obj;
8042 MaybeObject* maybe_object = arguments->GetElement(i);
8043 // This if() is not expected to fail, but we have the check in the
8044 // interest of hardening the runtime calls.
8045 if (maybe_object->ToObject(&obj)) {
8046 uint32_t length_estimate;
8047 if (obj->IsJSArray()) {
8048 length_estimate =
8049 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
8050 } else {
8051 length_estimate = 1;
8052 }
8053 if (JSObject::kMaxElementCount - result_length < length_estimate) {
8054 result_length = JSObject::kMaxElementCount;
8055 break;
8056 }
8057 result_length += length_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008058 }
8059 }
8060 }
8061
8062 // Allocate an empty array, will set length and content later.
8063 Handle<JSArray> result = Factory::NewJSArray(0);
8064
8065 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
8066 // If estimated number of elements is more than half of length, a
8067 // fixed array (fast case) is more time and space-efficient than a
8068 // dictionary.
8069 bool fast_case = (estimate_nof_elements * 2) >= result_length;
8070
8071 Handle<FixedArray> storage;
8072 if (fast_case) {
8073 // The backing storage array must have non-existing elements to
8074 // preserve holes across concat operations.
8075 storage = Factory::NewFixedArrayWithHoles(result_length);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008076 Handle<Map> fast_map =
8077 Factory::GetFastElementsMap(Handle<Map>(result->map()));
8078 result->set_map(*fast_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008079 } else {
8080 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8081 uint32_t at_least_space_for = estimate_nof_elements +
8082 (estimate_nof_elements >> 2);
8083 storage = Handle<FixedArray>::cast(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008084 Factory::NewNumberDictionary(at_least_space_for));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008085 Handle<Map> slow_map =
8086 Factory::GetSlowElementsMap(Handle<Map>(result->map()));
8087 result->set_map(*slow_map);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008088 }
8089
8090 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
8091
8092 ArrayConcatVisitor visitor(storage, result_length, fast_case);
8093
8094 IterateArguments(arguments, &visitor);
8095
8096 result->set_length(*len);
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008097 // Please note the storage might have changed in the visitor.
8098 result->set_elements(*visitor.storage());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008099
8100 return *result;
8101}
8102
8103
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008104// This will not allocate (flatten the string), but it may run
8105// very slowly for very deeply nested ConsStrings. For debugging use only.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008106static MaybeObject* Runtime_GlobalPrint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008107 NoHandleAllocation ha;
8108 ASSERT(args.length() == 1);
8109
8110 CONVERT_CHECKED(String, string, args[0]);
8111 StringInputBuffer buffer(string);
8112 while (buffer.has_more()) {
8113 uint16_t character = buffer.GetNext();
8114 PrintF("%c", character);
8115 }
8116 return string;
8117}
8118
ager@chromium.org5ec48922009-05-05 07:25:34 +00008119// Moves all own elements of an object, that are below a limit, to positions
8120// starting at zero. All undefined values are placed after non-undefined values,
8121// and are followed by non-existing element. Does not change the length
8122// property.
8123// Returns the number of non-undefined elements collected.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008124static MaybeObject* Runtime_RemoveArrayHoles(Arguments args) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008125 ASSERT(args.length() == 2);
8126 CONVERT_CHECKED(JSObject, object, args[0]);
8127 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
8128 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008129}
8130
8131
8132// Move contents of argument 0 (an array) to argument 1 (an array)
lrn@chromium.org303ada72010-10-27 09:33:13 +00008133static MaybeObject* Runtime_MoveArrayContents(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008134 ASSERT(args.length() == 2);
8135 CONVERT_CHECKED(JSArray, from, args[0]);
8136 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008137 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008138 MaybeObject* maybe_new_map;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00008139 if (new_elements->map() == Heap::fixed_array_map() ||
8140 new_elements->map() == Heap::fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008141 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008142 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008143 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008144 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008145 Object* new_map;
8146 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008147 to->set_map(Map::cast(new_map));
8148 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008149 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008150 Object* obj;
8151 { MaybeObject* maybe_obj = from->ResetElements();
8152 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8153 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008154 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008155 return to;
8156}
8157
8158
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008159// How many elements does this object/array have?
lrn@chromium.org303ada72010-10-27 09:33:13 +00008160static MaybeObject* Runtime_EstimateNumberOfElements(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008161 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008162 CONVERT_CHECKED(JSObject, object, args[0]);
8163 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008164 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008165 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008166 } else if (object->IsJSArray()) {
8167 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008168 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008169 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008170 }
8171}
8172
8173
lrn@chromium.org303ada72010-10-27 09:33:13 +00008174static MaybeObject* Runtime_SwapElements(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008175 HandleScope handle_scope;
8176
8177 ASSERT_EQ(3, args.length());
8178
ager@chromium.orgac091b72010-05-05 07:34:42 +00008179 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008180 Handle<Object> key1 = args.at<Object>(1);
8181 Handle<Object> key2 = args.at<Object>(2);
8182
8183 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008184 if (!key1->ToArrayIndex(&index1)
8185 || !key2->ToArrayIndex(&index2)) {
ager@chromium.orgac091b72010-05-05 07:34:42 +00008186 return Top::ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008187 }
8188
ager@chromium.orgac091b72010-05-05 07:34:42 +00008189 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
8190 Handle<Object> tmp1 = GetElement(jsobject, index1);
8191 Handle<Object> tmp2 = GetElement(jsobject, index2);
8192
8193 SetElement(jsobject, index1, tmp2);
8194 SetElement(jsobject, index2, tmp1);
8195
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008196 return Heap::undefined_value();
8197}
8198
8199
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008200// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008201// might have elements. Can either return keys (positive integers) or
8202// intervals (pair of a negative integer (-start-1) followed by a
8203// positive (length)) or undefined values.
8204// Intervals can span over some keys that are not in the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008205static MaybeObject* Runtime_GetArrayKeys(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008206 ASSERT(args.length() == 2);
8207 HandleScope scope;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008208 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008209 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008210 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008211 // Create an array and get all the keys into it, then remove all the
8212 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008213 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008214 int keys_length = keys->length();
8215 for (int i = 0; i < keys_length; i++) {
8216 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008217 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008218 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008219 // Zap invalid keys.
8220 keys->set_undefined(i);
8221 }
8222 }
8223 return *Factory::NewJSArrayWithElements(keys);
8224 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008225 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008226 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
8227 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008228 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008229 uint32_t actual_length =
8230 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00008231 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008232 Handle<Object> length_object =
ager@chromium.org5ec48922009-05-05 07:25:34 +00008233 Factory::NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008234 single_interval->set(1, *length_object);
8235 return *Factory::NewJSArrayWithElements(single_interval);
8236 }
8237}
8238
8239
8240// DefineAccessor takes an optional final argument which is the
8241// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
8242// to the way accessors are implemented, it is set for both the getter
8243// and setter on the first call to DefineAccessor and ignored on
8244// subsequent calls.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008245static MaybeObject* Runtime_DefineAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008246 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
8247 // Compute attributes.
8248 PropertyAttributes attributes = NONE;
8249 if (args.length() == 5) {
8250 CONVERT_CHECKED(Smi, attrs, args[4]);
8251 int value = attrs->value();
8252 // Only attribute bits should be set.
8253 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
8254 attributes = static_cast<PropertyAttributes>(value);
8255 }
8256
8257 CONVERT_CHECKED(JSObject, obj, args[0]);
8258 CONVERT_CHECKED(String, name, args[1]);
8259 CONVERT_CHECKED(Smi, flag, args[2]);
8260 CONVERT_CHECKED(JSFunction, fun, args[3]);
8261 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
8262}
8263
8264
lrn@chromium.org303ada72010-10-27 09:33:13 +00008265static MaybeObject* Runtime_LookupAccessor(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008266 ASSERT(args.length() == 3);
8267 CONVERT_CHECKED(JSObject, obj, args[0]);
8268 CONVERT_CHECKED(String, name, args[1]);
8269 CONVERT_CHECKED(Smi, flag, args[2]);
8270 return obj->LookupAccessor(name, flag->value() == 0);
8271}
8272
8273
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008274#ifdef ENABLE_DEBUGGER_SUPPORT
lrn@chromium.org303ada72010-10-27 09:33:13 +00008275static MaybeObject* Runtime_DebugBreak(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008276 ASSERT(args.length() == 0);
8277 return Execution::DebugBreakHelper();
8278}
8279
8280
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008281// Helper functions for wrapping and unwrapping stack frame ids.
8282static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008283 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008284 return Smi::FromInt(id >> 2);
8285}
8286
8287
8288static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
8289 return static_cast<StackFrame::Id>(wrapped->value() << 2);
8290}
8291
8292
8293// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00008294// args[0]: debug event listener function to set or null or undefined for
8295// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008296// args[1]: object supplied during callback
lrn@chromium.org303ada72010-10-27 09:33:13 +00008297static MaybeObject* Runtime_SetDebugEventListener(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008298 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008299 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
8300 args[0]->IsUndefined() ||
8301 args[0]->IsNull());
8302 Handle<Object> callback = args.at<Object>(0);
8303 Handle<Object> data = args.at<Object>(1);
8304 Debugger::SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008305
8306 return Heap::undefined_value();
8307}
8308
8309
lrn@chromium.org303ada72010-10-27 09:33:13 +00008310static MaybeObject* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00008311 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008312 StackGuard::DebugBreak();
8313 return Heap::undefined_value();
8314}
8315
8316
lrn@chromium.org303ada72010-10-27 09:33:13 +00008317static MaybeObject* DebugLookupResultValue(Object* receiver, String* name,
8318 LookupResult* result,
8319 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008320 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008321 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008322 case NORMAL:
8323 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008324 if (value->IsTheHole()) {
8325 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008326 }
8327 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008328 case FIELD:
8329 value =
8330 JSObject::cast(
8331 result->holder())->FastPropertyAt(result->GetFieldIndex());
8332 if (value->IsTheHole()) {
8333 return Heap::undefined_value();
8334 }
8335 return value;
8336 case CONSTANT_FUNCTION:
8337 return result->GetConstantFunction();
8338 case CALLBACKS: {
8339 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008340 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008341 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008342 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008343 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008344 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008345 ASSERT(maybe_value->IsException());
8346 maybe_value = Top::pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008347 Top::clear_pending_exception();
8348 if (caught_exception != NULL) {
8349 *caught_exception = true;
8350 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008351 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00008352 }
8353 return value;
8354 } else {
8355 return Heap::undefined_value();
8356 }
8357 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008358 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008359 case MAP_TRANSITION:
8360 case CONSTANT_TRANSITION:
8361 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008362 return Heap::undefined_value();
8363 default:
8364 UNREACHABLE();
8365 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008366 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008367 return Heap::undefined_value();
8368}
8369
8370
ager@chromium.org32912102009-01-16 10:38:43 +00008371// Get debugger related details for an object property.
8372// args[0]: object holding property
8373// args[1]: name of the property
8374//
8375// The array returned contains the following information:
8376// 0: Property value
8377// 1: Property details
8378// 2: Property value is exception
8379// 3: Getter function if defined
8380// 4: Setter function if defined
8381// Items 2-4 are only filled if the property has either a getter or a setter
8382// defined through __defineGetter__ and/or __defineSetter__.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008383static MaybeObject* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008384 HandleScope scope;
8385
8386 ASSERT(args.length() == 2);
8387
8388 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8389 CONVERT_ARG_CHECKED(String, name, 1);
8390
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00008391 // Make sure to set the current context to the context before the debugger was
8392 // entered (if the debugger is entered). The reason for switching context here
8393 // is that for some property lookups (accessors and interceptors) callbacks
8394 // into the embedding application can occour, and the embedding application
8395 // could have the assumption that its own global context is the current
8396 // context and not some internal debugger context.
8397 SaveContext save;
8398 if (Debug::InDebugger()) {
8399 Top::set_context(*Debug::debugger_entry()->GetContext());
8400 }
8401
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008402 // Skip the global proxy as it has no properties and always delegates to the
8403 // real global object.
8404 if (obj->IsJSGlobalProxy()) {
8405 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
8406 }
8407
8408
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008409 // Check if the name is trivially convertible to an index and get the element
8410 // if so.
8411 uint32_t index;
8412 if (name->AsArrayIndex(&index)) {
8413 Handle<FixedArray> details = Factory::NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008414 Object* element_or_char;
8415 { MaybeObject* maybe_element_or_char =
8416 Runtime::GetElementOrCharAt(obj, index);
8417 if (!maybe_element_or_char->ToObject(&element_or_char)) {
8418 return maybe_element_or_char;
8419 }
8420 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008421 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008422 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
8423 return *Factory::NewJSArrayWithElements(details);
8424 }
8425
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008426 // Find the number of objects making up this.
8427 int length = LocalPrototypeChainLength(*obj);
8428
8429 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008430 Handle<JSObject> jsproto = obj;
8431 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008432 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008433 jsproto->LocalLookup(*name, &result);
8434 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008435 // LookupResult is not GC safe as it holds raw object pointers.
8436 // GC can happen later in this code so put the required fields into
8437 // local variables using handles when required for later use.
8438 PropertyType result_type = result.type();
8439 Handle<Object> result_callback_obj;
8440 if (result_type == CALLBACKS) {
8441 result_callback_obj = Handle<Object>(result.GetCallbackObject());
8442 }
8443 Smi* property_details = result.GetPropertyDetails().AsSmi();
8444 // DebugLookupResultValue can cause GC so details from LookupResult needs
8445 // to be copied to handles before this.
8446 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008447 Object* raw_value;
8448 { MaybeObject* maybe_raw_value =
8449 DebugLookupResultValue(*obj, *name, &result, &caught_exception);
8450 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
8451 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008452 Handle<Object> value(raw_value);
8453
8454 // If the callback object is a fixed array then it contains JavaScript
8455 // getter and/or setter.
8456 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
8457 result_callback_obj->IsFixedArray();
8458 Handle<FixedArray> details =
8459 Factory::NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
8460 details->set(0, *value);
8461 details->set(1, property_details);
8462 if (hasJavaScriptAccessors) {
8463 details->set(2,
8464 caught_exception ? Heap::true_value()
8465 : Heap::false_value());
8466 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
8467 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
8468 }
8469
8470 return *Factory::NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008471 }
8472 if (i < length - 1) {
8473 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
8474 }
8475 }
8476
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008477 return Heap::undefined_value();
8478}
8479
8480
lrn@chromium.org303ada72010-10-27 09:33:13 +00008481static MaybeObject* Runtime_DebugGetProperty(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008482 HandleScope scope;
8483
8484 ASSERT(args.length() == 2);
8485
8486 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8487 CONVERT_ARG_CHECKED(String, name, 1);
8488
8489 LookupResult result;
8490 obj->Lookup(*name, &result);
8491 if (result.IsProperty()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008492 return DebugLookupResultValue(*obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008493 }
8494 return Heap::undefined_value();
8495}
8496
8497
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008498// Return the property type calculated from the property details.
8499// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008500static MaybeObject* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008501 ASSERT(args.length() == 1);
8502 CONVERT_CHECKED(Smi, details, args[0]);
8503 PropertyType type = PropertyDetails(details).type();
8504 return Smi::FromInt(static_cast<int>(type));
8505}
8506
8507
8508// Return the property attribute calculated from the property details.
8509// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008510static MaybeObject* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008511 ASSERT(args.length() == 1);
8512 CONVERT_CHECKED(Smi, details, args[0]);
8513 PropertyAttributes attributes = PropertyDetails(details).attributes();
8514 return Smi::FromInt(static_cast<int>(attributes));
8515}
8516
8517
8518// Return the property insertion index calculated from the property details.
8519// args[0]: smi with property details.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008520static MaybeObject* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008521 ASSERT(args.length() == 1);
8522 CONVERT_CHECKED(Smi, details, args[0]);
8523 int index = PropertyDetails(details).index();
8524 return Smi::FromInt(index);
8525}
8526
8527
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008528// Return property value from named interceptor.
8529// args[0]: object
8530// args[1]: property name
lrn@chromium.org303ada72010-10-27 09:33:13 +00008531static MaybeObject* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008532 HandleScope scope;
8533 ASSERT(args.length() == 2);
8534 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8535 RUNTIME_ASSERT(obj->HasNamedInterceptor());
8536 CONVERT_ARG_CHECKED(String, name, 1);
8537
8538 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008539 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008540}
8541
8542
8543// Return element value from indexed interceptor.
8544// args[0]: object
8545// args[1]: index
lrn@chromium.org303ada72010-10-27 09:33:13 +00008546static MaybeObject* Runtime_DebugIndexedInterceptorElementValue(
8547 Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008548 HandleScope scope;
8549 ASSERT(args.length() == 2);
8550 CONVERT_ARG_CHECKED(JSObject, obj, 0);
8551 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
8552 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
8553
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008554 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008555}
8556
8557
lrn@chromium.org303ada72010-10-27 09:33:13 +00008558static MaybeObject* Runtime_CheckExecutionState(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008559 ASSERT(args.length() >= 1);
8560 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00008561 // Check that the break id is valid.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008562 if (Debug::break_id() == 0 || break_id != Debug::break_id()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008563 return Top::Throw(Heap::illegal_execution_state_symbol());
8564 }
8565
8566 return Heap::true_value();
8567}
8568
8569
lrn@chromium.org303ada72010-10-27 09:33:13 +00008570static MaybeObject* Runtime_GetFrameCount(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008571 HandleScope scope;
8572 ASSERT(args.length() == 1);
8573
8574 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008575 Object* result;
8576 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
8577 if (!maybe_result->ToObject(&result)) return maybe_result;
8578 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008579
8580 // Count all frames which are relevant to debugging stack trace.
8581 int n = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008582 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008583 if (id == StackFrame::NO_ID) {
8584 // If there is no JavaScript stack frame count is 0.
8585 return Smi::FromInt(0);
8586 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008587 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
8588 return Smi::FromInt(n);
8589}
8590
8591
8592static const int kFrameDetailsFrameIdIndex = 0;
8593static const int kFrameDetailsReceiverIndex = 1;
8594static const int kFrameDetailsFunctionIndex = 2;
8595static const int kFrameDetailsArgumentCountIndex = 3;
8596static const int kFrameDetailsLocalCountIndex = 4;
8597static const int kFrameDetailsSourcePositionIndex = 5;
8598static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008599static const int kFrameDetailsAtReturnIndex = 7;
8600static const int kFrameDetailsDebuggerFrameIndex = 8;
8601static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008602
8603// Return an array with frame details
8604// args[0]: number: break id
8605// args[1]: number: frame index
8606//
8607// The array returned contains the following information:
8608// 0: Frame id
8609// 1: Receiver
8610// 2: Function
8611// 3: Argument count
8612// 4: Local count
8613// 5: Source position
8614// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008615// 7: Is at return
8616// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008617// Arguments name, value
8618// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008619// Return value if any
lrn@chromium.org303ada72010-10-27 09:33:13 +00008620static MaybeObject* Runtime_GetFrameDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008621 HandleScope scope;
8622 ASSERT(args.length() == 2);
8623
8624 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008625 Object* check;
8626 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
8627 if (!maybe_check->ToObject(&check)) return maybe_check;
8628 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008629 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
8630
8631 // Find the relevant frame with the requested index.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008632 StackFrame::Id id = Debug::break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00008633 if (id == StackFrame::NO_ID) {
8634 // If there are no JavaScript stack frames return undefined.
8635 return Heap::undefined_value();
8636 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008637 int count = 0;
8638 JavaScriptFrameIterator it(id);
8639 for (; !it.done(); it.Advance()) {
8640 if (count == index) break;
8641 count++;
8642 }
8643 if (it.done()) return Heap::undefined_value();
8644
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008645 bool is_optimized_frame =
8646 it.frame()->code()->kind() == Code::OPTIMIZED_FUNCTION;
8647
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008648 // Traverse the saved contexts chain to find the active context for the
8649 // selected frame.
8650 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008651 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008652 save = save->prev();
8653 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008654 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008655
8656 // Get the frame id.
8657 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
8658
8659 // Find source position.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00008660 int position = it.frame()->code()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008661
8662 // Check for constructor frame.
8663 bool constructor = it.frame()->IsConstructor();
8664
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008665 // Get scope info and read from it for local variable information.
8666 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00008667 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008668 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008669
8670 // Get the context.
8671 Handle<Context> context(Context::cast(it.frame()->context()));
8672
8673 // Get the locals names and values into a temporary array.
8674 //
8675 // TODO(1240907): Hide compiler-introduced stack variables
8676 // (e.g. .result)? For users of the debugger, they will probably be
8677 // confusing.
8678 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008679
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008680 // Fill in the names of the locals.
8681 for (int i = 0; i < info.NumberOfLocals(); i++) {
8682 locals->set(i * 2, *info.LocalName(i));
8683 }
8684
8685 // Fill in the values of the locals.
8686 for (int i = 0; i < info.NumberOfLocals(); i++) {
8687 if (is_optimized_frame) {
8688 // If we are inspecting an optimized frame use undefined as the
8689 // value for all locals.
8690 //
8691 // TODO(3141533): We should be able to get the correct values
8692 // for locals in optimized frames.
8693 locals->set(i * 2 + 1, Heap::undefined_value());
8694 } else if (i < info.number_of_stack_slots()) {
8695 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008696 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
8697 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008698 // Traverse the context chain to the function context as all local
8699 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008700 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008701 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008702 context = Handle<Context>(context->previous());
8703 }
8704 ASSERT(context->is_function_context());
8705 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00008706 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008707 }
8708 }
8709
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008710 // Check whether this frame is positioned at return. If not top
8711 // frame or if the frame is optimized it cannot be at a return.
8712 bool at_return = false;
8713 if (!is_optimized_frame && index == 0) {
8714 at_return = Debug::IsBreakAtReturn(it.frame());
8715 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008716
8717 // If positioned just before return find the value to be returned and add it
8718 // to the frame information.
8719 Handle<Object> return_value = Factory::undefined_value();
8720 if (at_return) {
8721 StackFrameIterator it2;
8722 Address internal_frame_sp = NULL;
8723 while (!it2.done()) {
8724 if (it2.frame()->is_internal()) {
8725 internal_frame_sp = it2.frame()->sp();
8726 } else {
8727 if (it2.frame()->is_java_script()) {
8728 if (it2.frame()->id() == it.frame()->id()) {
8729 // The internal frame just before the JavaScript frame contains the
8730 // value to return on top. A debug break at return will create an
8731 // internal frame to store the return value (eax/rax/r0) before
8732 // entering the debug break exit frame.
8733 if (internal_frame_sp != NULL) {
8734 return_value =
8735 Handle<Object>(Memory::Object_at(internal_frame_sp));
8736 break;
8737 }
8738 }
8739 }
8740
8741 // Indicate that the previous frame was not an internal frame.
8742 internal_frame_sp = NULL;
8743 }
8744 it2.Advance();
8745 }
8746 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008747
8748 // Now advance to the arguments adapter frame (if any). It contains all
8749 // the provided parameters whereas the function frame always have the number
8750 // of arguments matching the functions parameters. The rest of the
8751 // information (except for what is collected above) is the same.
8752 it.AdvanceToArgumentsFrame();
8753
8754 // Find the number of arguments to fill. At least fill the number of
8755 // parameters for the function and fill more if more parameters are provided.
8756 int argument_count = info.number_of_parameters();
8757 if (argument_count < it.frame()->GetProvidedParametersCount()) {
8758 argument_count = it.frame()->GetProvidedParametersCount();
8759 }
8760
8761 // Calculate the size of the result.
8762 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008763 2 * (argument_count + info.NumberOfLocals()) +
8764 (at_return ? 1 : 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008765 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
8766
8767 // Add the frame id.
8768 details->set(kFrameDetailsFrameIdIndex, *frame_id);
8769
8770 // Add the function (same as in function frame).
8771 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
8772
8773 // Add the arguments count.
8774 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
8775
8776 // Add the locals count
8777 details->set(kFrameDetailsLocalCountIndex,
8778 Smi::FromInt(info.NumberOfLocals()));
8779
8780 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00008781 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008782 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
8783 } else {
8784 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
8785 }
8786
8787 // Add the constructor information.
8788 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
8789
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008790 // Add the at return information.
8791 details->set(kFrameDetailsAtReturnIndex, Heap::ToBoolean(at_return));
8792
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008793 // Add information on whether this frame is invoked in the debugger context.
8794 details->set(kFrameDetailsDebuggerFrameIndex,
8795 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
8796
8797 // Fill the dynamic part.
8798 int details_index = kFrameDetailsFirstDynamicIndex;
8799
8800 // Add arguments name and value.
8801 for (int i = 0; i < argument_count; i++) {
8802 // Name of the argument.
8803 if (i < info.number_of_parameters()) {
8804 details->set(details_index++, *info.parameter_name(i));
8805 } else {
8806 details->set(details_index++, Heap::undefined_value());
8807 }
8808
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008809 // Parameter value. If we are inspecting an optimized frame, use
8810 // undefined as the value.
8811 //
8812 // TODO(3141533): We should be able to get the actual parameter
8813 // value for optimized frames.
8814 if (!is_optimized_frame &&
8815 (i < it.frame()->GetProvidedParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008816 details->set(details_index++, it.frame()->GetParameter(i));
8817 } else {
8818 details->set(details_index++, Heap::undefined_value());
8819 }
8820 }
8821
8822 // Add locals name and value from the temporary copy from the function frame.
8823 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
8824 details->set(details_index++, locals->get(i));
8825 }
8826
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00008827 // Add the value being returned.
8828 if (at_return) {
8829 details->set(details_index++, *return_value);
8830 }
8831
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008832 // Add the receiver (same as in function frame).
8833 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
8834 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
8835 Handle<Object> receiver(it.frame()->receiver());
8836 if (!receiver->IsJSObject()) {
8837 // If the receiver is NOT a JSObject we have hit an optimization
8838 // where a value object is not converted into a wrapped JS objects.
8839 // To hide this optimization from the debugger, we wrap the receiver
8840 // by creating correct wrapper object based on the calling frame's
8841 // global context.
8842 it.Advance();
8843 Handle<Context> calling_frames_global_context(
8844 Context::cast(Context::cast(it.frame()->context())->global_context()));
8845 receiver = Factory::ToObject(receiver, calling_frames_global_context);
8846 }
8847 details->set(kFrameDetailsReceiverIndex, *receiver);
8848
8849 ASSERT_EQ(details_size, details_index);
8850 return *Factory::NewJSArrayWithElements(details);
8851}
8852
8853
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008854// Copy all the context locals into an object used to materialize a scope.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008855static void CopyContextLocalsToScopeObject(
8856 Handle<SerializedScopeInfo> serialized_scope_info,
8857 ScopeInfo<>& scope_info,
8858 Handle<Context> context,
8859 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008860 // Fill all context locals to the context extension.
8861 for (int i = Context::MIN_CONTEXT_SLOTS;
8862 i < scope_info.number_of_context_slots();
8863 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00008864 int context_index = serialized_scope_info->ContextSlotIndex(
8865 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008866
8867 // Don't include the arguments shadow (.arguments) context variable.
8868 if (*scope_info.context_slot_name(i) != Heap::arguments_shadow_symbol()) {
8869 SetProperty(scope_object,
8870 scope_info.context_slot_name(i),
8871 Handle<Object>(context->get(context_index)), NONE);
8872 }
8873 }
8874}
8875
8876
8877// Create a plain JSObject which materializes the local scope for the specified
8878// frame.
8879static Handle<JSObject> MaterializeLocalScope(JavaScriptFrame* frame) {
8880 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008881 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008882 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8883 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008884
8885 // Allocate and initialize a JSObject with all the arguments, stack locals
8886 // heap locals and extension properties of the debugged function.
8887 Handle<JSObject> local_scope = Factory::NewJSObject(Top::object_function());
8888
8889 // First fill all parameters.
8890 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
8891 SetProperty(local_scope,
8892 scope_info.parameter_name(i),
8893 Handle<Object>(frame->GetParameter(i)), NONE);
8894 }
8895
8896 // Second fill all stack locals.
8897 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
8898 SetProperty(local_scope,
8899 scope_info.stack_slot_name(i),
8900 Handle<Object>(frame->GetExpression(i)), NONE);
8901 }
8902
8903 // Third fill all context locals.
8904 Handle<Context> frame_context(Context::cast(frame->context()));
8905 Handle<Context> function_context(frame_context->fcontext());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008906 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008907 function_context, local_scope);
8908
8909 // Finally copy any properties from the function context extension. This will
8910 // be variables introduced by eval.
8911 if (function_context->closure() == *function) {
8912 if (function_context->has_extension() &&
8913 !function_context->IsGlobalContext()) {
8914 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008915 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008916 for (int i = 0; i < keys->length(); i++) {
8917 // Names of variables introduced by eval are strings.
8918 ASSERT(keys->get(i)->IsString());
8919 Handle<String> key(String::cast(keys->get(i)));
8920 SetProperty(local_scope, key, GetProperty(ext, key), NONE);
8921 }
8922 }
8923 }
8924 return local_scope;
8925}
8926
8927
8928// Create a plain JSObject which materializes the closure content for the
8929// context.
8930static Handle<JSObject> MaterializeClosure(Handle<Context> context) {
8931 ASSERT(context->is_function_context());
8932
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00008933 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00008934 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
8935 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008936
8937 // Allocate and initialize a JSObject with all the content of theis function
8938 // closure.
8939 Handle<JSObject> closure_scope = Factory::NewJSObject(Top::object_function());
8940
8941 // Check whether the arguments shadow object exists.
8942 int arguments_shadow_index =
ager@chromium.orgb5737492010-07-15 09:29:43 +00008943 shared->scope_info()->ContextSlotIndex(Heap::arguments_shadow_symbol(),
8944 NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008945 if (arguments_shadow_index >= 0) {
8946 // In this case all the arguments are available in the arguments shadow
8947 // object.
8948 Handle<JSObject> arguments_shadow(
8949 JSObject::cast(context->get(arguments_shadow_index)));
8950 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008951 // We don't expect exception-throwing getters on the arguments shadow.
8952 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008953 SetProperty(closure_scope,
8954 scope_info.parameter_name(i),
lrn@chromium.org303ada72010-10-27 09:33:13 +00008955 Handle<Object>(element),
8956 NONE);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008957 }
8958 }
8959
8960 // Fill all context locals to the context extension.
ager@chromium.orgb5737492010-07-15 09:29:43 +00008961 CopyContextLocalsToScopeObject(serialized_scope_info, scope_info,
8962 context, closure_scope);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008963
8964 // Finally copy any properties from the function context extension. This will
8965 // be variables introduced by eval.
8966 if (context->has_extension()) {
8967 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008968 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008969 for (int i = 0; i < keys->length(); i++) {
8970 // Names of variables introduced by eval are strings.
8971 ASSERT(keys->get(i)->IsString());
8972 Handle<String> key(String::cast(keys->get(i)));
8973 SetProperty(closure_scope, key, GetProperty(ext, key), NONE);
8974 }
8975 }
8976
8977 return closure_scope;
8978}
8979
8980
8981// Iterate over the actual scopes visible from a stack frame. All scopes are
8982// backed by an actual context except the local scope, which is inserted
8983// "artifically" in the context chain.
8984class ScopeIterator {
8985 public:
8986 enum ScopeType {
8987 ScopeTypeGlobal = 0,
8988 ScopeTypeLocal,
8989 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00008990 ScopeTypeClosure,
8991 // Every catch block contains an implicit with block (its parameter is
8992 // a JSContextExtensionObject) that extends current scope with a variable
8993 // holding exception object. Such with blocks are treated as scopes of their
8994 // own type.
8995 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008996 };
8997
8998 explicit ScopeIterator(JavaScriptFrame* frame)
8999 : frame_(frame),
9000 function_(JSFunction::cast(frame->function())),
9001 context_(Context::cast(frame->context())),
9002 local_done_(false),
9003 at_local_(false) {
9004
9005 // Check whether the first scope is actually a local scope.
9006 if (context_->IsGlobalContext()) {
9007 // If there is a stack slot for .result then this local scope has been
9008 // created for evaluating top level code and it is not a real local scope.
9009 // Checking for the existence of .result seems fragile, but the scope info
9010 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009011 int index = function_->shared()->scope_info()->
9012 StackSlotIndex(Heap::result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009013 at_local_ = index < 0;
9014 } else if (context_->is_function_context()) {
9015 at_local_ = true;
9016 }
9017 }
9018
9019 // More scopes?
9020 bool Done() { return context_.is_null(); }
9021
9022 // Move to the next scope.
9023 void Next() {
9024 // If at a local scope mark the local scope as passed.
9025 if (at_local_) {
9026 at_local_ = false;
9027 local_done_ = true;
9028
9029 // If the current context is not associated with the local scope the
9030 // current context is the next real scope, so don't move to the next
9031 // context in this case.
9032 if (context_->closure() != *function_) {
9033 return;
9034 }
9035 }
9036
9037 // The global scope is always the last in the chain.
9038 if (context_->IsGlobalContext()) {
9039 context_ = Handle<Context>();
9040 return;
9041 }
9042
9043 // Move to the next context.
9044 if (context_->is_function_context()) {
9045 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
9046 } else {
9047 context_ = Handle<Context>(context_->previous());
9048 }
9049
9050 // If passing the local scope indicate that the current scope is now the
9051 // local scope.
9052 if (!local_done_ &&
9053 (context_->IsGlobalContext() || (context_->is_function_context()))) {
9054 at_local_ = true;
9055 }
9056 }
9057
9058 // Return the type of the current scope.
9059 int Type() {
9060 if (at_local_) {
9061 return ScopeTypeLocal;
9062 }
9063 if (context_->IsGlobalContext()) {
9064 ASSERT(context_->global()->IsGlobalObject());
9065 return ScopeTypeGlobal;
9066 }
9067 if (context_->is_function_context()) {
9068 return ScopeTypeClosure;
9069 }
9070 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00009071 // Current scope is either an explicit with statement or a with statement
9072 // implicitely generated for a catch block.
9073 // If the extension object here is a JSContextExtensionObject then
9074 // current with statement is one frome a catch block otherwise it's a
9075 // regular with statement.
9076 if (context_->extension()->IsJSContextExtensionObject()) {
9077 return ScopeTypeCatch;
9078 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009079 return ScopeTypeWith;
9080 }
9081
9082 // Return the JavaScript object with the content of the current scope.
9083 Handle<JSObject> ScopeObject() {
9084 switch (Type()) {
9085 case ScopeIterator::ScopeTypeGlobal:
9086 return Handle<JSObject>(CurrentContext()->global());
9087 break;
9088 case ScopeIterator::ScopeTypeLocal:
9089 // Materialize the content of the local scope into a JSObject.
9090 return MaterializeLocalScope(frame_);
9091 break;
9092 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00009093 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009094 // Return the with object.
9095 return Handle<JSObject>(CurrentContext()->extension());
9096 break;
9097 case ScopeIterator::ScopeTypeClosure:
9098 // Materialize the content of the closure scope into a JSObject.
9099 return MaterializeClosure(CurrentContext());
9100 break;
9101 }
9102 UNREACHABLE();
9103 return Handle<JSObject>();
9104 }
9105
9106 // Return the context for this scope. For the local context there might not
9107 // be an actual context.
9108 Handle<Context> CurrentContext() {
9109 if (at_local_ && context_->closure() != *function_) {
9110 return Handle<Context>();
9111 }
9112 return context_;
9113 }
9114
9115#ifdef DEBUG
9116 // Debug print of the content of the current scope.
9117 void DebugPrint() {
9118 switch (Type()) {
9119 case ScopeIterator::ScopeTypeGlobal:
9120 PrintF("Global:\n");
9121 CurrentContext()->Print();
9122 break;
9123
9124 case ScopeIterator::ScopeTypeLocal: {
9125 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009126 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009127 scope_info.Print();
9128 if (!CurrentContext().is_null()) {
9129 CurrentContext()->Print();
9130 if (CurrentContext()->has_extension()) {
9131 Handle<JSObject> extension =
9132 Handle<JSObject>(CurrentContext()->extension());
9133 if (extension->IsJSContextExtensionObject()) {
9134 extension->Print();
9135 }
9136 }
9137 }
9138 break;
9139 }
9140
9141 case ScopeIterator::ScopeTypeWith: {
9142 PrintF("With:\n");
9143 Handle<JSObject> extension =
9144 Handle<JSObject>(CurrentContext()->extension());
9145 extension->Print();
9146 break;
9147 }
9148
ager@chromium.orga1645e22009-09-09 19:27:10 +00009149 case ScopeIterator::ScopeTypeCatch: {
9150 PrintF("Catch:\n");
9151 Handle<JSObject> extension =
9152 Handle<JSObject>(CurrentContext()->extension());
9153 extension->Print();
9154 break;
9155 }
9156
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009157 case ScopeIterator::ScopeTypeClosure: {
9158 PrintF("Closure:\n");
9159 CurrentContext()->Print();
9160 if (CurrentContext()->has_extension()) {
9161 Handle<JSObject> extension =
9162 Handle<JSObject>(CurrentContext()->extension());
9163 if (extension->IsJSContextExtensionObject()) {
9164 extension->Print();
9165 }
9166 }
9167 break;
9168 }
9169
9170 default:
9171 UNREACHABLE();
9172 }
9173 PrintF("\n");
9174 }
9175#endif
9176
9177 private:
9178 JavaScriptFrame* frame_;
9179 Handle<JSFunction> function_;
9180 Handle<Context> context_;
9181 bool local_done_;
9182 bool at_local_;
9183
9184 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
9185};
9186
9187
lrn@chromium.org303ada72010-10-27 09:33:13 +00009188static MaybeObject* Runtime_GetScopeCount(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009189 HandleScope scope;
9190 ASSERT(args.length() == 2);
9191
9192 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009193 Object* check;
9194 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9195 if (!maybe_check->ToObject(&check)) return maybe_check;
9196 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009197 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9198
9199 // Get the frame where the debugging is performed.
9200 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9201 JavaScriptFrameIterator it(id);
9202 JavaScriptFrame* frame = it.frame();
9203
9204 // Count the visible scopes.
9205 int n = 0;
9206 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9207 n++;
9208 }
9209
9210 return Smi::FromInt(n);
9211}
9212
9213
9214static const int kScopeDetailsTypeIndex = 0;
9215static const int kScopeDetailsObjectIndex = 1;
9216static const int kScopeDetailsSize = 2;
9217
9218// Return an array with scope details
9219// args[0]: number: break id
9220// args[1]: number: frame index
9221// args[2]: number: scope index
9222//
9223// The array returned contains the following information:
9224// 0: Scope type
9225// 1: Scope object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009226static MaybeObject* Runtime_GetScopeDetails(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009227 HandleScope scope;
9228 ASSERT(args.length() == 3);
9229
9230 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009231 Object* check;
9232 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9233 if (!maybe_check->ToObject(&check)) return maybe_check;
9234 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009235 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9236 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
9237
9238 // Get the frame where the debugging is performed.
9239 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9240 JavaScriptFrameIterator frame_it(id);
9241 JavaScriptFrame* frame = frame_it.frame();
9242
9243 // Find the requested scope.
9244 int n = 0;
9245 ScopeIterator it(frame);
9246 for (; !it.Done() && n < index; it.Next()) {
9247 n++;
9248 }
9249 if (it.Done()) {
9250 return Heap::undefined_value();
9251 }
9252
9253 // Calculate the size of the result.
9254 int details_size = kScopeDetailsSize;
9255 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
9256
9257 // Fill in scope details.
9258 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009259 Handle<JSObject> scope_object = it.ScopeObject();
9260 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009261
9262 return *Factory::NewJSArrayWithElements(details);
9263}
9264
9265
lrn@chromium.org303ada72010-10-27 09:33:13 +00009266static MaybeObject* Runtime_DebugPrintScopes(Arguments args) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009267 HandleScope scope;
9268 ASSERT(args.length() == 0);
9269
9270#ifdef DEBUG
9271 // Print the scopes for the top frame.
9272 StackFrameLocator locator;
9273 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
9274 for (ScopeIterator it(frame); !it.Done(); it.Next()) {
9275 it.DebugPrint();
9276 }
9277#endif
9278 return Heap::undefined_value();
9279}
9280
9281
lrn@chromium.org303ada72010-10-27 09:33:13 +00009282static MaybeObject* Runtime_GetThreadCount(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009283 HandleScope scope;
9284 ASSERT(args.length() == 1);
9285
9286 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009287 Object* result;
9288 { MaybeObject* maybe_result = Runtime_CheckExecutionState(args);
9289 if (!maybe_result->ToObject(&result)) return maybe_result;
9290 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009291
9292 // Count all archived V8 threads.
9293 int n = 0;
9294 for (ThreadState* thread = ThreadState::FirstInUse();
9295 thread != NULL;
9296 thread = thread->Next()) {
9297 n++;
9298 }
9299
9300 // Total number of threads is current thread and archived threads.
9301 return Smi::FromInt(n + 1);
9302}
9303
9304
9305static const int kThreadDetailsCurrentThreadIndex = 0;
9306static const int kThreadDetailsThreadIdIndex = 1;
9307static const int kThreadDetailsSize = 2;
9308
9309// Return an array with thread details
9310// args[0]: number: break id
9311// args[1]: number: thread index
9312//
9313// The array returned contains the following information:
9314// 0: Is current thread?
9315// 1: Thread id
lrn@chromium.org303ada72010-10-27 09:33:13 +00009316static MaybeObject* Runtime_GetThreadDetails(Arguments args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009317 HandleScope scope;
9318 ASSERT(args.length() == 2);
9319
9320 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009321 Object* check;
9322 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9323 if (!maybe_check->ToObject(&check)) return maybe_check;
9324 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009325 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
9326
9327 // Allocate array for result.
9328 Handle<FixedArray> details = Factory::NewFixedArray(kThreadDetailsSize);
9329
9330 // Thread index 0 is current thread.
9331 if (index == 0) {
9332 // Fill the details.
9333 details->set(kThreadDetailsCurrentThreadIndex, Heap::true_value());
9334 details->set(kThreadDetailsThreadIdIndex,
9335 Smi::FromInt(ThreadManager::CurrentId()));
9336 } else {
9337 // Find the thread with the requested index.
9338 int n = 1;
9339 ThreadState* thread = ThreadState::FirstInUse();
9340 while (index != n && thread != NULL) {
9341 thread = thread->Next();
9342 n++;
9343 }
9344 if (thread == NULL) {
9345 return Heap::undefined_value();
9346 }
9347
9348 // Fill the details.
9349 details->set(kThreadDetailsCurrentThreadIndex, Heap::false_value());
9350 details->set(kThreadDetailsThreadIdIndex, Smi::FromInt(thread->id()));
9351 }
9352
9353 // Convert to JS array and return.
9354 return *Factory::NewJSArrayWithElements(details);
9355}
9356
9357
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009358// Sets the disable break state
9359// args[0]: disable break state
lrn@chromium.org303ada72010-10-27 09:33:13 +00009360static MaybeObject* Runtime_SetDisableBreak(Arguments args) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00009361 HandleScope scope;
9362 ASSERT(args.length() == 1);
9363 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
9364 Debug::set_disable_break(disable_break);
9365 return Heap::undefined_value();
9366}
9367
9368
lrn@chromium.org303ada72010-10-27 09:33:13 +00009369static MaybeObject* Runtime_GetBreakLocations(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009370 HandleScope scope;
9371 ASSERT(args.length() == 1);
9372
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009373 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9374 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009375 // Find the number of break points
9376 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
9377 if (break_locations->IsUndefined()) return Heap::undefined_value();
9378 // Return array as JS array
9379 return *Factory::NewJSArrayWithElements(
9380 Handle<FixedArray>::cast(break_locations));
9381}
9382
9383
9384// Set a break point in a function
9385// args[0]: function
9386// args[1]: number: break source position (within the function source)
9387// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009388static MaybeObject* Runtime_SetFunctionBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009389 HandleScope scope;
9390 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00009391 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
9392 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009393 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9394 RUNTIME_ASSERT(source_position >= 0);
9395 Handle<Object> break_point_object_arg = args.at<Object>(2);
9396
9397 // Set break point.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009398 Debug::SetBreakPoint(shared, break_point_object_arg, &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009399
lrn@chromium.org32d961d2010-06-30 09:09:34 +00009400 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009401}
9402
9403
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009404Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
9405 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009406 // Iterate the heap looking for SharedFunctionInfo generated from the
9407 // script. The inner most SharedFunctionInfo containing the source position
9408 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009409 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009410 // which is found is not compiled it is compiled and the heap is iterated
9411 // again as the compilation might create inner functions from the newly
9412 // compiled function and the actual requested break point might be in one of
9413 // these functions.
9414 bool done = false;
9415 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00009416 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009417 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009418 while (!done) {
9419 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009420 for (HeapObject* obj = iterator.next();
9421 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009422 if (obj->IsSharedFunctionInfo()) {
9423 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
9424 if (shared->script() == *script) {
9425 // If the SharedFunctionInfo found has the requested script data and
9426 // contains the source position it is a candidate.
9427 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00009428 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009429 start_position = shared->start_position();
9430 }
9431 if (start_position <= position &&
9432 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +00009433 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009434 // candidate this is the new candidate.
9435 if (target.is_null()) {
9436 target_start_position = start_position;
9437 target = shared;
9438 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00009439 if (target_start_position == start_position &&
9440 shared->end_position() == target->end_position()) {
9441 // If a top-level function contain only one function
9442 // declartion the source for the top-level and the function is
9443 // the same. In that case prefer the non top-level function.
9444 if (!shared->is_toplevel()) {
9445 target_start_position = start_position;
9446 target = shared;
9447 }
9448 } else if (target_start_position <= start_position &&
9449 shared->end_position() <= target->end_position()) {
9450 // This containment check includes equality as a function inside
9451 // a top-level function can share either start or end position
9452 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009453 target_start_position = start_position;
9454 target = shared;
9455 }
9456 }
9457 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009458 }
9459 }
9460 }
9461
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009462 if (target.is_null()) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009463 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009464 }
9465
9466 // If the candidate found is compiled we are done. NOTE: when lazy
9467 // compilation of inner functions is introduced some additional checking
9468 // needs to be done here to compile inner functions.
9469 done = target->is_compiled();
9470 if (!done) {
9471 // If the candidate is not compiled compile it to reveal any inner
9472 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009473 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009474 }
9475 }
9476
9477 return *target;
9478}
9479
9480
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009481// Changes the state of a break point in a script and returns source position
9482// where break point was set. NOTE: Regarding performance see the NOTE for
9483// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009484// args[0]: script to set break point in
9485// args[1]: number: break source position (within the script source)
9486// args[2]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009487static MaybeObject* Runtime_SetScriptBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009488 HandleScope scope;
9489 ASSERT(args.length() == 3);
9490 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
9491 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
9492 RUNTIME_ASSERT(source_position >= 0);
9493 Handle<Object> break_point_object_arg = args.at<Object>(2);
9494
9495 // Get the script from the script wrapper.
9496 RUNTIME_ASSERT(wrapper->value()->IsScript());
9497 Handle<Script> script(Script::cast(wrapper->value()));
9498
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009499 Object* result = Runtime::FindSharedFunctionInfoInScript(
9500 script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009501 if (!result->IsUndefined()) {
9502 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
9503 // Find position within function. The script position might be before the
9504 // source position of the first function.
9505 int position;
9506 if (shared->start_position() > source_position) {
9507 position = 0;
9508 } else {
9509 position = source_position - shared->start_position();
9510 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00009511 Debug::SetBreakPoint(shared, break_point_object_arg, &position);
9512 position += shared->start_position();
9513 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009514 }
9515 return Heap::undefined_value();
9516}
9517
9518
9519// Clear a break point
9520// args[0]: number: break point object
lrn@chromium.org303ada72010-10-27 09:33:13 +00009521static MaybeObject* Runtime_ClearBreakPoint(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009522 HandleScope scope;
9523 ASSERT(args.length() == 1);
9524 Handle<Object> break_point_object_arg = args.at<Object>(0);
9525
9526 // Clear break point.
9527 Debug::ClearBreakPoint(break_point_object_arg);
9528
9529 return Heap::undefined_value();
9530}
9531
9532
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009533// Change the state of break on exceptions.
9534// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
9535// args[1]: Boolean indicating on/off.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009536static MaybeObject* Runtime_ChangeBreakOnException(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009537 HandleScope scope;
9538 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009539 RUNTIME_ASSERT(args[0]->IsNumber());
9540 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009541
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009542 // If the number doesn't match an enum value, the ChangeBreakOnException
9543 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009544 ExceptionBreakType type =
9545 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009546 // Update break point state.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009547 Debug::ChangeBreakOnException(type, enable);
9548 return Heap::undefined_value();
9549}
9550
9551
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009552// Returns the state of break on exceptions
9553// args[0]: boolean indicating uncaught exceptions
lrn@chromium.org303ada72010-10-27 09:33:13 +00009554static MaybeObject* Runtime_IsBreakOnException(Arguments args) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009555 HandleScope scope;
9556 ASSERT(args.length() == 1);
9557 RUNTIME_ASSERT(args[0]->IsNumber());
9558
9559 ExceptionBreakType type =
9560 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
9561 bool result = Debug::IsBreakOnException(type);
9562 return Smi::FromInt(result);
9563}
9564
9565
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009566// Prepare for stepping
9567// args[0]: break id for checking execution state
9568// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +00009569// args[2]: number of times to perform the step, for step out it is the number
9570// of frames to step down.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009571static MaybeObject* Runtime_PrepareStep(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009572 HandleScope scope;
9573 ASSERT(args.length() == 3);
9574 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009575 Object* check;
9576 { MaybeObject* maybe_check = Runtime_CheckExecutionState(args);
9577 if (!maybe_check->ToObject(&check)) return maybe_check;
9578 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009579 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
9580 return Top::Throw(Heap::illegal_argument_symbol());
9581 }
9582
9583 // Get the step action and check validity.
9584 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
9585 if (step_action != StepIn &&
9586 step_action != StepNext &&
9587 step_action != StepOut &&
9588 step_action != StepInMin &&
9589 step_action != StepMin) {
9590 return Top::Throw(Heap::illegal_argument_symbol());
9591 }
9592
9593 // Get the number of steps.
9594 int step_count = NumberToInt32(args[2]);
9595 if (step_count < 1) {
9596 return Top::Throw(Heap::illegal_argument_symbol());
9597 }
9598
ager@chromium.orga1645e22009-09-09 19:27:10 +00009599 // Clear all current stepping setup.
9600 Debug::ClearStepping();
9601
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009602 // Prepare step.
9603 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
9604 return Heap::undefined_value();
9605}
9606
9607
9608// Clear all stepping set by PrepareStep.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009609static MaybeObject* Runtime_ClearStepping(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009610 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009611 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009612 Debug::ClearStepping();
9613 return Heap::undefined_value();
9614}
9615
9616
9617// Creates a copy of the with context chain. The copy of the context chain is
9618// is linked to the function context supplied.
9619static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
9620 Handle<Context> function_context) {
9621 // At the bottom of the chain. Return the function context to link to.
9622 if (context_chain->is_function_context()) {
9623 return function_context;
9624 }
9625
9626 // Recursively copy the with contexts.
9627 Handle<Context> previous(context_chain->previous());
9628 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009629 Handle<Context> context = CopyWithContextChain(function_context, previous);
9630 return Factory::NewWithContext(context,
9631 extension,
9632 context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009633}
9634
9635
9636// Helper function to find or create the arguments object for
9637// Runtime_DebugEvaluate.
9638static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
9639 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009640 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009641 const ScopeInfo<>* sinfo,
9642 Handle<Context> function_context) {
9643 // Try to find the value of 'arguments' to pass as parameter. If it is not
9644 // found (that is the debugged function does not reference 'arguments' and
9645 // does not support eval) then create an 'arguments' object.
9646 int index;
9647 if (sinfo->number_of_stack_slots() > 0) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009648 index = scope_info->StackSlotIndex(Heap::arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009649 if (index != -1) {
9650 return Handle<Object>(frame->GetExpression(index));
9651 }
9652 }
9653
9654 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009655 index = scope_info->ContextSlotIndex(Heap::arguments_symbol(), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009656 if (index != -1) {
9657 return Handle<Object>(function_context->get(index));
9658 }
9659 }
9660
9661 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009662 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
9663 Handle<FixedArray> array = Factory::NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009664
9665 AssertNoAllocation no_gc;
9666 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009667 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009668 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009669 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009670 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009671 return arguments;
9672}
9673
9674
9675// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +00009676// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009677// extension part has all the parameters and locals of the function on the
9678// stack frame. A function which calls eval with the code to evaluate is then
9679// compiled in this context and called in this context. As this context
9680// replaces the context of the function on the stack frame a new (empty)
9681// function is created as well to be used as the closure for the context.
9682// This function and the context acts as replacements for the function on the
9683// stack frame presenting the same view of the values of parameters and
9684// local variables as if the piece of JavaScript was evaluated at the point
9685// where the function on the stack frame is currently stopped.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009686static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009687 HandleScope scope;
9688
9689 // Check the execution state and decode arguments frame and source to be
9690 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009691 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009692 Object* check_result;
9693 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9694 if (!maybe_check_result->ToObject(&check_result)) {
9695 return maybe_check_result;
9696 }
9697 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009698 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
9699 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009700 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
9701
9702 // Handle the processing of break.
9703 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009704
9705 // Get the frame where the debugging is performed.
9706 StackFrame::Id id = UnwrapFrameId(wrapped_id);
9707 JavaScriptFrameIterator it(id);
9708 JavaScriptFrame* frame = it.frame();
9709 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009710 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009711 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009712
9713 // Traverse the saved contexts chain to find the active context for the
9714 // selected frame.
9715 SaveContext* save = Top::save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009716 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009717 save = save->prev();
9718 }
9719 ASSERT(save != NULL);
9720 SaveContext savex;
9721 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009722
9723 // Create the (empty) function replacing the function on the stack frame for
9724 // the purpose of evaluating in the context created below. It is important
9725 // that this function does not describe any parameters and local variables
9726 // in the context. If it does then this will cause problems with the lookup
9727 // in Context::Lookup, where context slots for parameters and local variables
9728 // are looked at before the extension object.
9729 Handle<JSFunction> go_between =
9730 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
9731 go_between->set_context(function->context());
9732#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009733 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009734 ASSERT(go_between_sinfo.number_of_parameters() == 0);
9735 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
9736#endif
9737
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009738 // Materialize the content of the local scope into a JSObject.
9739 Handle<JSObject> local_scope = MaterializeLocalScope(frame);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009740
9741 // Allocate a new context for the debug evaluation and set the extension
9742 // object build.
9743 Handle<Context> context =
9744 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009745 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009746 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009747 Handle<Context> frame_context(Context::cast(frame->context()));
9748 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009749 context = CopyWithContextChain(frame_context, context);
9750
9751 // Wrap the evaluation statement in a new function compiled in the newly
9752 // created context. The function has one parameter which has to be called
9753 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +00009754 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009755 // function(arguments,__source__) {return eval(__source__);}
9756 static const char* source_str =
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009757 "(function(arguments,__source__){return eval(__source__);})";
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009758 static const int source_str_length = StrLength(source_str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009759 Handle<String> function_source =
9760 Factory::NewStringFromAscii(Vector<const char>(source_str,
9761 source_str_length));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009762 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +00009763 Compiler::CompileEval(function_source,
9764 context,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009765 context->IsGlobalContext());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009766 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009767 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009768 Factory::NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009769
9770 // Invoke the result of the compilation to get the evaluation function.
9771 bool has_pending_exception;
9772 Handle<Object> receiver(frame->receiver());
9773 Handle<Object> evaluation_function =
9774 Execution::Call(compiled_function, receiver, 0, NULL,
9775 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009776 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009777
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009778 Handle<Object> arguments = GetArgumentsObject(frame, function, scope_info,
9779 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009780
9781 // Invoke the evaluation function and return the result.
9782 const int argc = 2;
9783 Object** argv[argc] = { arguments.location(),
9784 Handle<Object>::cast(source).location() };
9785 Handle<Object> result =
9786 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
9787 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009788 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009789
9790 // Skip the global proxy as it has no properties and always delegates to the
9791 // real global object.
9792 if (result->IsJSGlobalProxy()) {
9793 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
9794 }
9795
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009796 return *result;
9797}
9798
9799
lrn@chromium.org303ada72010-10-27 09:33:13 +00009800static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009801 HandleScope scope;
9802
9803 // Check the execution state and decode arguments frame and source to be
9804 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009805 ASSERT(args.length() == 3);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009806 Object* check_result;
9807 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(args);
9808 if (!maybe_check_result->ToObject(&check_result)) {
9809 return maybe_check_result;
9810 }
9811 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009812 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00009813 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
9814
9815 // Handle the processing of break.
9816 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009817
9818 // Enter the top context from before the debugger was invoked.
9819 SaveContext save;
9820 SaveContext* top = &save;
9821 while (top != NULL && *top->context() == *Debug::debug_context()) {
9822 top = top->prev();
9823 }
9824 if (top != NULL) {
9825 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009826 }
9827
9828 // Get the global context now set to the top context from before the
9829 // debugger was invoked.
9830 Handle<Context> context = Top::global_context();
9831
9832 // Compile the source to be evaluated.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009833 Handle<SharedFunctionInfo> shared =
9834 Compiler::CompileEval(source,
9835 context,
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009836 true);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009837 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009838 Handle<JSFunction> compiled_function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009839 Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
9840 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009841
9842 // Invoke the result of the compilation to get the evaluation function.
9843 bool has_pending_exception;
9844 Handle<Object> receiver = Top::global();
9845 Handle<Object> result =
9846 Execution::Call(compiled_function, receiver, 0, NULL,
9847 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00009848 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009849 return *result;
9850}
9851
9852
lrn@chromium.org303ada72010-10-27 09:33:13 +00009853static MaybeObject* Runtime_DebugGetLoadedScripts(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009854 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00009855 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009856
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009857 // Fill the script objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009858 Handle<FixedArray> instances = Debug::GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009859
9860 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009861 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00009862 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
9863 // Get the script wrapper in a local handle before calling GetScriptWrapper,
9864 // because using
9865 // instances->set(i, *GetScriptWrapper(script))
9866 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
9867 // already have deferenced the instances handle.
9868 Handle<JSValue> wrapper = GetScriptWrapper(script);
9869 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009870 }
9871
9872 // Return result as a JS array.
9873 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
9874 Handle<JSArray>::cast(result)->SetContent(*instances);
9875 return *result;
9876}
9877
9878
9879// Helper function used by Runtime_DebugReferencedBy below.
9880static int DebugReferencedBy(JSObject* target,
9881 Object* instance_filter, int max_references,
9882 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009883 JSFunction* arguments_function) {
9884 NoHandleAllocation ha;
9885 AssertNoAllocation no_alloc;
9886
9887 // Iterate the heap.
9888 int count = 0;
9889 JSObject* last = NULL;
9890 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009891 HeapObject* heap_obj = NULL;
9892 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009893 (max_references == 0 || count < max_references)) {
9894 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009895 if (heap_obj->IsJSObject()) {
9896 // Skip context extension objects and argument arrays as these are
9897 // checked in the context of functions using them.
9898 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009899 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009900 obj->map()->constructor() == arguments_function) {
9901 continue;
9902 }
9903
9904 // Check if the JS object has a reference to the object looked for.
9905 if (obj->ReferencesObject(target)) {
9906 // Check instance filter if supplied. This is normally used to avoid
9907 // references from mirror objects (see Runtime_IsInPrototypeChain).
9908 if (!instance_filter->IsUndefined()) {
9909 Object* V = obj;
9910 while (true) {
9911 Object* prototype = V->GetPrototype();
9912 if (prototype->IsNull()) {
9913 break;
9914 }
9915 if (instance_filter == prototype) {
9916 obj = NULL; // Don't add this object.
9917 break;
9918 }
9919 V = prototype;
9920 }
9921 }
9922
9923 if (obj != NULL) {
9924 // Valid reference found add to instance array if supplied an update
9925 // count.
9926 if (instances != NULL && count < instances_size) {
9927 instances->set(count, obj);
9928 }
9929 last = obj;
9930 count++;
9931 }
9932 }
9933 }
9934 }
9935
9936 // Check for circular reference only. This can happen when the object is only
9937 // referenced from mirrors and has a circular reference in which case the
9938 // object is not really alive and would have been garbage collected if not
9939 // referenced from the mirror.
9940 if (count == 1 && last == target) {
9941 count = 0;
9942 }
9943
9944 // Return the number of referencing objects found.
9945 return count;
9946}
9947
9948
9949// Scan the heap for objects with direct references to an object
9950// args[0]: the object to find references to
9951// args[1]: constructor function for instances to exclude (Mirror)
9952// args[2]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +00009953static MaybeObject* Runtime_DebugReferencedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009954 ASSERT(args.length() == 3);
9955
9956 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00009957 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009958
9959 // Check parameters.
9960 CONVERT_CHECKED(JSObject, target, args[0]);
9961 Object* instance_filter = args[1];
9962 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
9963 instance_filter->IsJSObject());
9964 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
9965 RUNTIME_ASSERT(max_references >= 0);
9966
9967 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009968 JSObject* arguments_boilerplate =
9969 Top::context()->global_context()->arguments_boilerplate();
9970 JSFunction* arguments_function =
9971 JSFunction::cast(arguments_boilerplate->map()->constructor());
9972
9973 // Get the number of referencing objects.
9974 int count;
9975 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00009976 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009977
9978 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009979 Object* object;
9980 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
9981 if (!maybe_object->ToObject(&object)) return maybe_object;
9982 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009983 FixedArray* instances = FixedArray::cast(object);
9984
9985 // Fill the referencing objects.
9986 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +00009987 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009988
9989 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009990 Object* result;
9991 { MaybeObject* maybe_result = Heap::AllocateJSObject(
9992 Top::context()->global_context()->array_function());
9993 if (!maybe_result->ToObject(&result)) return maybe_result;
9994 }
9995 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009996 return result;
9997}
9998
9999
10000// Helper function used by Runtime_DebugConstructedBy below.
10001static int DebugConstructedBy(JSFunction* constructor, int max_references,
10002 FixedArray* instances, int instances_size) {
10003 AssertNoAllocation no_alloc;
10004
10005 // Iterate the heap.
10006 int count = 0;
10007 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010008 HeapObject* heap_obj = NULL;
10009 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010010 (max_references == 0 || count < max_references)) {
10011 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010012 if (heap_obj->IsJSObject()) {
10013 JSObject* obj = JSObject::cast(heap_obj);
10014 if (obj->map()->constructor() == constructor) {
10015 // Valid reference found add to instance array if supplied an update
10016 // count.
10017 if (instances != NULL && count < instances_size) {
10018 instances->set(count, obj);
10019 }
10020 count++;
10021 }
10022 }
10023 }
10024
10025 // Return the number of referencing objects found.
10026 return count;
10027}
10028
10029
10030// Scan the heap for objects constructed by a specific function.
10031// args[0]: the constructor to find instances of
10032// args[1]: the the maximum number of objects to return
lrn@chromium.org303ada72010-10-27 09:33:13 +000010033static MaybeObject* Runtime_DebugConstructedBy(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010034 ASSERT(args.length() == 2);
10035
10036 // First perform a full GC in order to avoid dead objects.
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010037 Heap::CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010038
10039 // Check parameters.
10040 CONVERT_CHECKED(JSFunction, constructor, args[0]);
10041 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
10042 RUNTIME_ASSERT(max_references >= 0);
10043
10044 // Get the number of referencing objects.
10045 int count;
10046 count = DebugConstructedBy(constructor, max_references, NULL, 0);
10047
10048 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010049 Object* object;
10050 { MaybeObject* maybe_object = Heap::AllocateFixedArray(count);
10051 if (!maybe_object->ToObject(&object)) return maybe_object;
10052 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010053 FixedArray* instances = FixedArray::cast(object);
10054
10055 // Fill the referencing objects.
10056 count = DebugConstructedBy(constructor, max_references, instances, count);
10057
10058 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010059 Object* result;
10060 { MaybeObject* maybe_result = Heap::AllocateJSObject(
10061 Top::context()->global_context()->array_function());
10062 if (!maybe_result->ToObject(&result)) return maybe_result;
10063 }
10064 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010065 return result;
10066}
10067
10068
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010069// Find the effective prototype object as returned by __proto__.
10070// args[0]: the object to find the prototype for.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010071static MaybeObject* Runtime_DebugGetPrototype(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010072 ASSERT(args.length() == 1);
10073
10074 CONVERT_CHECKED(JSObject, obj, args[0]);
10075
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010076 // Use the __proto__ accessor.
10077 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010078}
10079
10080
lrn@chromium.org303ada72010-10-27 09:33:13 +000010081static MaybeObject* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010082 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010083 CPU::DebugBreak();
10084 return Heap::undefined_value();
10085}
10086
10087
lrn@chromium.org303ada72010-10-27 09:33:13 +000010088static MaybeObject* Runtime_DebugDisassembleFunction(Arguments args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010089#ifdef DEBUG
10090 HandleScope scope;
10091 ASSERT(args.length() == 1);
10092 // Get the function and make sure it is compiled.
10093 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010094 Handle<SharedFunctionInfo> shared(func->shared());
10095 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010096 return Failure::Exception();
10097 }
10098 func->code()->PrintLn();
10099#endif // DEBUG
10100 return Heap::undefined_value();
10101}
ager@chromium.org9085a012009-05-11 19:22:57 +000010102
10103
lrn@chromium.org303ada72010-10-27 09:33:13 +000010104static MaybeObject* Runtime_DebugDisassembleConstructor(Arguments args) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010105#ifdef DEBUG
10106 HandleScope scope;
10107 ASSERT(args.length() == 1);
10108 // Get the function and make sure it is compiled.
10109 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010110 Handle<SharedFunctionInfo> shared(func->shared());
10111 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010112 return Failure::Exception();
10113 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010114 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000010115#endif // DEBUG
10116 return Heap::undefined_value();
10117}
10118
10119
lrn@chromium.org303ada72010-10-27 09:33:13 +000010120static MaybeObject* Runtime_FunctionGetInferredName(Arguments args) {
ager@chromium.org9085a012009-05-11 19:22:57 +000010121 NoHandleAllocation ha;
10122 ASSERT(args.length() == 1);
10123
10124 CONVERT_CHECKED(JSFunction, f, args[0]);
10125 return f->shared()->inferred_name();
10126}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010127
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010128
10129static int FindSharedFunctionInfosForScript(Script* script,
10130 FixedArray* buffer) {
10131 AssertNoAllocation no_allocations;
10132
10133 int counter = 0;
10134 int buffer_size = buffer->length();
10135 HeapIterator iterator;
10136 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
10137 ASSERT(obj != NULL);
10138 if (!obj->IsSharedFunctionInfo()) {
10139 continue;
10140 }
10141 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
10142 if (shared->script() != script) {
10143 continue;
10144 }
10145 if (counter < buffer_size) {
10146 buffer->set(counter, shared);
10147 }
10148 counter++;
10149 }
10150 return counter;
10151}
10152
10153// For a script finds all SharedFunctionInfo's in the heap that points
10154// to this script. Returns JSArray of SharedFunctionInfo wrapped
10155// in OpaqueReferences.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010156static MaybeObject* Runtime_LiveEditFindSharedFunctionInfosForScript(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010157 Arguments args) {
10158 ASSERT(args.length() == 1);
10159 HandleScope scope;
10160 CONVERT_CHECKED(JSValue, script_value, args[0]);
10161
10162 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
10163
10164 const int kBufferSize = 32;
10165
10166 Handle<FixedArray> array;
10167 array = Factory::NewFixedArray(kBufferSize);
10168 int number = FindSharedFunctionInfosForScript(*script, *array);
10169 if (number > kBufferSize) {
10170 array = Factory::NewFixedArray(number);
10171 FindSharedFunctionInfosForScript(*script, *array);
10172 }
10173
10174 Handle<JSArray> result = Factory::NewJSArrayWithElements(array);
10175 result->set_length(Smi::FromInt(number));
10176
10177 LiveEdit::WrapSharedFunctionInfos(result);
10178
10179 return *result;
10180}
10181
10182// For a script calculates compilation information about all its functions.
10183// The script source is explicitly specified by the second argument.
10184// The source of the actual script is not used, however it is important that
10185// all generated code keeps references to this particular instance of script.
10186// Returns a JSArray of compilation infos. The array is ordered so that
10187// each function with all its descendant is always stored in a continues range
10188// with the function itself going first. The root function is a script function.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010189static MaybeObject* Runtime_LiveEditGatherCompileInfo(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010190 ASSERT(args.length() == 2);
10191 HandleScope scope;
10192 CONVERT_CHECKED(JSValue, script, args[0]);
10193 CONVERT_ARG_CHECKED(String, source, 1);
10194 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
10195
10196 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
10197
10198 if (Top::has_pending_exception()) {
10199 return Failure::Exception();
10200 }
10201
10202 return result;
10203}
10204
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010205// Changes the source of the script to a new_source.
10206// If old_script_name is provided (i.e. is a String), also creates a copy of
10207// the script with its original source and sends notification to debugger.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010208static MaybeObject* Runtime_LiveEditReplaceScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010209 ASSERT(args.length() == 3);
10210 HandleScope scope;
10211 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
10212 CONVERT_ARG_CHECKED(String, new_source, 1);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010213 Handle<Object> old_script_name(args[2]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010214
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010215 CONVERT_CHECKED(Script, original_script_pointer,
10216 original_script_value->value());
10217 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010218
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010219 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
10220 new_source,
10221 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010222
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010223 if (old_script->IsScript()) {
10224 Handle<Script> script_handle(Script::cast(old_script));
10225 return *(GetScriptWrapper(script_handle));
10226 } else {
10227 return Heap::null_value();
10228 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010229}
10230
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010231
10232static MaybeObject* Runtime_LiveEditFunctionSourceUpdated(Arguments args) {
10233 ASSERT(args.length() == 1);
10234 HandleScope scope;
10235 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
10236 return LiveEdit::FunctionSourceUpdated(shared_info);
10237}
10238
10239
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010240// Replaces code of SharedFunctionInfo with a new one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010241static MaybeObject* Runtime_LiveEditReplaceFunctionCode(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010242 ASSERT(args.length() == 2);
10243 HandleScope scope;
10244 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
10245 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
10246
ager@chromium.orgac091b72010-05-05 07:34:42 +000010247 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010248}
10249
10250// Connects SharedFunctionInfo to another script.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010251static MaybeObject* Runtime_LiveEditFunctionSetScript(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010252 ASSERT(args.length() == 2);
10253 HandleScope scope;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010254 Handle<Object> function_object(args[0]);
10255 Handle<Object> script_object(args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010256
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010257 if (function_object->IsJSValue()) {
10258 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
10259 if (script_object->IsJSValue()) {
10260 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
10261 script_object = Handle<Object>(script);
10262 }
10263
10264 LiveEdit::SetFunctionScript(function_wrapper, script_object);
10265 } else {
10266 // Just ignore this. We may not have a SharedFunctionInfo for some functions
10267 // and we check it in this function.
10268 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010269
10270 return Heap::undefined_value();
10271}
10272
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010273
10274// In a code of a parent function replaces original function as embedded object
10275// with a substitution one.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010276static MaybeObject* Runtime_LiveEditReplaceRefToNestedFunction(Arguments args) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010277 ASSERT(args.length() == 3);
10278 HandleScope scope;
10279
10280 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
10281 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
10282 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
10283
10284 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
10285 subst_wrapper);
10286
10287 return Heap::undefined_value();
10288}
10289
10290
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010291// Updates positions of a shared function info (first parameter) according
10292// to script source change. Text change is described in second parameter as
10293// array of groups of 3 numbers:
10294// (change_begin, change_end, change_end_new_position).
10295// Each group describes a change in text; groups are sorted by change_begin.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010296static MaybeObject* Runtime_LiveEditPatchFunctionPositions(Arguments args) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010297 ASSERT(args.length() == 2);
10298 HandleScope scope;
10299 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
10300 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
10301
ager@chromium.orgac091b72010-05-05 07:34:42 +000010302 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010303}
10304
10305
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010306// For array of SharedFunctionInfo's (each wrapped in JSValue)
10307// checks that none of them have activations on stacks (of any thread).
10308// Returns array of the same length with corresponding results of
10309// LiveEdit::FunctionPatchabilityStatus type.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010310static MaybeObject* Runtime_LiveEditCheckAndDropActivations(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010311 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010312 HandleScope scope;
10313 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000010314 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010315
ager@chromium.org357bf652010-04-12 11:30:10 +000010316 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010317}
10318
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010319// Compares 2 strings line-by-line and returns diff in form of JSArray of
fschneider@chromium.org013f3e12010-04-26 13:27:52 +000010320// triplets (pos1, pos1_end, pos2_end) describing list of diff chunks.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010321static MaybeObject* Runtime_LiveEditCompareStringsLinewise(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010322 ASSERT(args.length() == 2);
10323 HandleScope scope;
10324 CONVERT_ARG_CHECKED(String, s1, 0);
10325 CONVERT_ARG_CHECKED(String, s2, 1);
10326
10327 return *LiveEdit::CompareStringsLinewise(s1, s2);
10328}
10329
10330
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010331
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010332// A testing entry. Returns statement position which is the closest to
10333// source_position.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010334static MaybeObject* Runtime_GetFunctionCodePositionFromSource(Arguments args) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010335 ASSERT(args.length() == 2);
10336 HandleScope scope;
10337 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10338 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10339
10340 Handle<Code> code(function->code());
10341
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010342 if (code->kind() != Code::FUNCTION &&
10343 code->kind() != Code::OPTIMIZED_FUNCTION) {
10344 return Heap::undefined_value();
10345 }
10346
10347 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010348 int closest_pc = 0;
10349 int distance = kMaxInt;
10350 while (!it.done()) {
10351 int statement_position = static_cast<int>(it.rinfo()->data());
10352 // Check if this break point is closer that what was previously found.
10353 if (source_position <= statement_position &&
10354 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000010355 closest_pc =
10356 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000010357 distance = statement_position - source_position;
10358 // Check whether we can't get any closer.
10359 if (distance == 0) break;
10360 }
10361 it.next();
10362 }
10363
10364 return Smi::FromInt(closest_pc);
10365}
10366
10367
ager@chromium.org357bf652010-04-12 11:30:10 +000010368// Calls specified function with or without entering the debugger.
10369// This is used in unit tests to run code as if debugger is entered or simply
10370// to have a stack with C++ frame in the middle.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010371static MaybeObject* Runtime_ExecuteInDebugContext(Arguments args) {
ager@chromium.org357bf652010-04-12 11:30:10 +000010372 ASSERT(args.length() == 2);
10373 HandleScope scope;
10374 CONVERT_ARG_CHECKED(JSFunction, function, 0);
10375 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
10376
10377 Handle<Object> result;
10378 bool pending_exception;
10379 {
10380 if (without_debugger) {
10381 result = Execution::Call(function, Top::global(), 0, NULL,
10382 &pending_exception);
10383 } else {
10384 EnterDebugger enter_debugger;
10385 result = Execution::Call(function, Top::global(), 0, NULL,
10386 &pending_exception);
10387 }
10388 }
10389 if (!pending_exception) {
10390 return *result;
10391 } else {
10392 return Failure::Exception();
10393 }
10394}
10395
10396
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010397#endif // ENABLE_DEBUGGER_SUPPORT
10398
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010399#ifdef ENABLE_LOGGING_AND_PROFILING
10400
lrn@chromium.org303ada72010-10-27 09:33:13 +000010401static MaybeObject* Runtime_ProfilerResume(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010402 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010403 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010404
10405 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010406 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10407 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010408 return Heap::undefined_value();
10409}
10410
10411
lrn@chromium.org303ada72010-10-27 09:33:13 +000010412static MaybeObject* Runtime_ProfilerPause(Arguments args) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010413 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000010414 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010415
10416 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000010417 CONVERT_CHECKED(Smi, smi_tag, args[1]);
10418 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010419 return Heap::undefined_value();
10420}
10421
10422#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010423
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010424// Finds the script object from the script data. NOTE: This operation uses
10425// heap traversal to find the function generated for the source position
10426// for the requested break point. For lazily compiled functions several heap
10427// traversals might be required rendering this operation as a rather slow
10428// operation. However for setting break points which is normally done through
10429// some kind of user interaction the performance is not crucial.
10430static Handle<Object> Runtime_GetScriptFromScriptName(
10431 Handle<String> script_name) {
10432 // Scan the heap for Script objects to find the script with the requested
10433 // script data.
10434 Handle<Script> script;
10435 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010436 HeapObject* obj = NULL;
10437 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010438 // If a script is found check if it has the script data requested.
10439 if (obj->IsScript()) {
10440 if (Script::cast(obj)->name()->IsString()) {
10441 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
10442 script = Handle<Script>(Script::cast(obj));
10443 }
10444 }
10445 }
10446 }
10447
10448 // If no script with the requested script data is found return undefined.
10449 if (script.is_null()) return Factory::undefined_value();
10450
10451 // Return the script found.
10452 return GetScriptWrapper(script);
10453}
10454
10455
10456// Get the script object from script data. NOTE: Regarding performance
10457// see the NOTE for GetScriptFromScriptData.
10458// args[0]: script data for the script to find the source for
lrn@chromium.org303ada72010-10-27 09:33:13 +000010459static MaybeObject* Runtime_GetScript(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010460 HandleScope scope;
10461
10462 ASSERT(args.length() == 1);
10463
10464 CONVERT_CHECKED(String, script_name, args[0]);
10465
10466 // Find the requested script.
10467 Handle<Object> result =
10468 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
10469 return *result;
10470}
10471
10472
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010473// Determines whether the given stack frame should be displayed in
10474// a stack trace. The caller is the error constructor that asked
10475// for the stack trace to be collected. The first time a construct
10476// call to this function is encountered it is skipped. The seen_caller
10477// in/out parameter is used to remember if the caller has been seen
10478// yet.
10479static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
10480 bool* seen_caller) {
10481 // Only display JS frames.
10482 if (!raw_frame->is_java_script())
10483 return false;
10484 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
10485 Object* raw_fun = frame->function();
10486 // Not sure when this can happen but skip it just in case.
10487 if (!raw_fun->IsJSFunction())
10488 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010489 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010490 *seen_caller = true;
10491 return false;
10492 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010493 // Skip all frames until we've seen the caller. Also, skip the most
10494 // obvious builtin calls. Some builtin calls (such as Number.ADD
10495 // which is invoked using 'call') are very difficult to recognize
10496 // so we're leaving them in for now.
10497 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010498}
10499
10500
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010501// Collect the raw data for a stack trace. Returns an array of 4
10502// element segments each containing a receiver, function, code and
10503// native code offset.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010504static MaybeObject* Runtime_CollectStackTrace(Arguments args) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010505 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010506 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010507 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
10508
10509 HandleScope scope;
10510
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000010511 limit = Max(limit, 0); // Ensure that limit is not negative.
10512 int initial_size = Min(limit, 10);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010513 Handle<JSArray> result = Factory::NewJSArray(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010514
10515 StackFrameIterator iter;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010516 // If the caller parameter is a function we skip frames until we're
10517 // under it before starting to collect.
10518 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010519 int cursor = 0;
10520 int frames_seen = 0;
10521 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010522 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010523 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010524 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010525 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010526 List<FrameSummary> frames(3); // Max 2 levels of inlining.
10527 frame->Summarize(&frames);
10528 for (int i = frames.length() - 1; i >= 0; i--) {
10529 Handle<Object> recv = frames[i].receiver();
10530 Handle<JSFunction> fun = frames[i].function();
10531 Handle<Code> code = frames[i].code();
10532 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
10533 FixedArray* elements = FixedArray::cast(result->elements());
10534 if (cursor + 3 < elements->length()) {
10535 elements->set(cursor++, *recv);
10536 elements->set(cursor++, *fun);
10537 elements->set(cursor++, *code);
10538 elements->set(cursor++, *offset);
10539 } else {
10540 SetElement(result, cursor++, recv);
10541 SetElement(result, cursor++, fun);
10542 SetElement(result, cursor++, code);
10543 SetElement(result, cursor++, offset);
10544 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010545 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010546 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010547 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010548 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010549
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010550 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010551 return *result;
10552}
10553
10554
ager@chromium.org3811b432009-10-28 14:53:37 +000010555// Returns V8 version as a string.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010556static MaybeObject* Runtime_GetV8Version(Arguments args) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010557 ASSERT_EQ(args.length(), 0);
10558
10559 NoHandleAllocation ha;
10560
10561 const char* version_string = v8::V8::GetVersion();
10562
10563 return Heap::AllocateStringFromAscii(CStrVector(version_string), NOT_TENURED);
10564}
10565
10566
lrn@chromium.org303ada72010-10-27 09:33:13 +000010567static MaybeObject* Runtime_Abort(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010568 ASSERT(args.length() == 2);
10569 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
10570 Smi::cast(args[1])->value());
10571 Top::PrintStack();
10572 OS::Abort();
10573 UNREACHABLE();
10574 return NULL;
10575}
10576
10577
lrn@chromium.org303ada72010-10-27 09:33:13 +000010578MUST_USE_RESULT static MaybeObject* CacheMiss(FixedArray* cache_obj,
10579 int index,
10580 Object* key_obj) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010581 ASSERT(index % 2 == 0); // index of the key
10582 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
10583 ASSERT(index < cache_obj->length());
10584
10585 HandleScope scope;
10586
10587 Handle<FixedArray> cache(cache_obj);
10588 Handle<Object> key(key_obj);
10589 Handle<JSFunction> factory(JSFunction::cast(
10590 cache->get(JSFunctionResultCache::kFactoryIndex)));
10591 // TODO(antonm): consider passing a receiver when constructing a cache.
10592 Handle<Object> receiver(Top::global_context()->global());
10593
10594 Handle<Object> value;
10595 {
10596 // This handle is nor shared, nor used later, so it's safe.
10597 Object** argv[] = { key.location() };
10598 bool pending_exception = false;
10599 value = Execution::Call(factory,
10600 receiver,
10601 1,
10602 argv,
10603 &pending_exception);
10604 if (pending_exception) return Failure::Exception();
10605 }
10606
10607 cache->set(index, *key);
10608 cache->set(index + 1, *value);
10609 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(index));
10610
10611 return *value;
10612}
10613
10614
lrn@chromium.org303ada72010-10-27 09:33:13 +000010615static MaybeObject* Runtime_GetFromCache(Arguments args) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010616 // This is only called from codegen, so checks might be more lax.
10617 CONVERT_CHECKED(FixedArray, cache, args[0]);
10618 Object* key = args[1];
10619
10620 const int finger_index =
10621 Smi::cast(cache->get(JSFunctionResultCache::kFingerIndex))->value();
10622
10623 Object* o = cache->get(finger_index);
10624 if (o == key) {
10625 // The fastest case: hit the same place again.
10626 return cache->get(finger_index + 1);
10627 }
10628
10629 for (int i = finger_index - 2;
10630 i >= JSFunctionResultCache::kEntriesIndex;
10631 i -= 2) {
10632 o = cache->get(i);
10633 if (o == key) {
10634 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i));
10635 return cache->get(i + 1);
10636 }
10637 }
10638
10639 const int size =
10640 Smi::cast(cache->get(JSFunctionResultCache::kCacheSizeIndex))->value();
10641 ASSERT(size <= cache->length());
10642
10643 for (int i = size - 2; i > finger_index; i -= 2) {
10644 o = cache->get(i);
10645 if (o == key) {
10646 cache->set(JSFunctionResultCache::kFingerIndex, Smi::FromInt(i));
10647 return cache->get(i + 1);
10648 }
10649 }
10650
10651 // Cache miss. If we have spare room, put new data into it, otherwise
10652 // evict post finger entry which must be least recently used.
10653 if (size < cache->length()) {
10654 cache->set(JSFunctionResultCache::kCacheSizeIndex, Smi::FromInt(size + 2));
10655 return CacheMiss(cache, size, key);
10656 } else {
antonm@chromium.org397e23c2010-04-21 12:00:05 +000010657 int target_index = finger_index + JSFunctionResultCache::kEntrySize;
10658 if (target_index == cache->length()) {
10659 target_index = JSFunctionResultCache::kEntriesIndex;
10660 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000010661 return CacheMiss(cache, target_index, key);
10662 }
10663}
10664
kasper.lund44510672008-07-25 07:37:58 +000010665#ifdef DEBUG
10666// ListNatives is ONLY used by the fuzz-natives.js in debug mode
10667// Exclude the code in release mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010668static MaybeObject* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +000010669 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010670 HandleScope scope;
10671 Handle<JSArray> result = Factory::NewJSArray(0);
10672 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010673 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010674#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010675 { \
10676 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010677 Handle<String> name; \
10678 /* Inline runtime functions have an underscore in front of the name. */ \
10679 if (inline_runtime_functions) { \
10680 name = Factory::NewStringFromAscii( \
10681 Vector<const char>("_" #Name, StrLength("_" #Name))); \
10682 } else { \
10683 name = Factory::NewStringFromAscii( \
10684 Vector<const char>(#Name, StrLength(#Name))); \
10685 } \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010686 Handle<JSArray> pair = Factory::NewJSArray(0); \
10687 SetElement(pair, 0, name); \
10688 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
10689 SetElement(result, index++, pair); \
10690 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010691 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010692 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010693 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010694 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010695 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010696#undef ADD_ENTRY
10697 return *result;
10698}
kasper.lund44510672008-07-25 07:37:58 +000010699#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010700
10701
lrn@chromium.org303ada72010-10-27 09:33:13 +000010702static MaybeObject* Runtime_Log(Arguments args) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010703 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010704 CONVERT_CHECKED(String, format, args[0]);
10705 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010706 Vector<const char> chars = format->ToAsciiVector();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000010707 Logger::LogRuntime(chars, elms);
10708 return Heap::undefined_value();
10709}
10710
10711
lrn@chromium.org303ada72010-10-27 09:33:13 +000010712static MaybeObject* Runtime_IS_VAR(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010713 UNREACHABLE(); // implemented as macro in the parser
10714 return NULL;
10715}
10716
10717
10718// ----------------------------------------------------------------------------
10719// Implementation of Runtime
10720
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010721#define F(name, number_of_args, result_size) \
10722 { Runtime::k##name, Runtime::RUNTIME, #name, \
10723 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010724
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010725
10726#define I(name, number_of_args, result_size) \
10727 { Runtime::kInline##name, Runtime::INLINE, \
10728 "_" #name, NULL, number_of_args, result_size },
10729
10730Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010731 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010732 INLINE_FUNCTION_LIST(I)
10733 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010734};
10735
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010736
lrn@chromium.org303ada72010-10-27 09:33:13 +000010737MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Object* dictionary) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010738 ASSERT(dictionary != NULL);
10739 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
10740 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010741 Object* name_symbol;
10742 { MaybeObject* maybe_name_symbol =
10743 Heap::LookupAsciiSymbol(kIntrinsicFunctions[i].name);
10744 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
10745 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010746 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010747 { MaybeObject* maybe_dictionary = string_dictionary->Add(
10748 String::cast(name_symbol),
10749 Smi::FromInt(i),
10750 PropertyDetails(NONE, NORMAL));
10751 if (!maybe_dictionary->ToObject(&dictionary)) {
10752 // Non-recoverable failure. Calling code must restart heap
10753 // initialization.
10754 return maybe_dictionary;
10755 }
10756 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010757 }
10758 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010759}
10760
10761
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010762Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
10763 int entry = Heap::intrinsic_function_names()->FindEntry(*name);
10764 if (entry != kNotFound) {
10765 Object* smi_index = Heap::intrinsic_function_names()->ValueAt(entry);
10766 int function_index = Smi::cast(smi_index)->value();
10767 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010768 }
10769 return NULL;
10770}
10771
10772
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000010773Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
10774 return &(kIntrinsicFunctions[static_cast<int>(id)]);
10775}
10776
10777
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010778void Runtime::PerformGC(Object* result) {
10779 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010780 if (failure->IsRetryAfterGC()) {
10781 // Try to do a garbage collection; ignore it if it fails. The C
10782 // entry stub will throw an out-of-memory exception in that case.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000010783 Heap::CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010784 } else {
10785 // Handle last resort GC and make sure to allow future allocations
10786 // to grow the heap without causing GCs (if possible).
10787 Counters::gc_last_resort_from_js.Increment();
ager@chromium.orgab99eea2009-08-25 07:05:41 +000010788 Heap::CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010789 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010790}
10791
10792
10793} } // namespace v8::internal