blob: a50303b65fc0c679be76b238f2765e41a077ae98 [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 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"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000043#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000045#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000046#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000047#include "liveobjectlist-inl.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000048#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000050#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000051#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000053#include "smart-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000055#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000056#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000058
kasperl@chromium.org71affb52009-05-26 05:44:31 +000059namespace v8 {
60namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
62
ager@chromium.org3e875802009-06-29 08:26:34 +000063#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000064 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065
66// Cast the given object to a value of the specified type and store
67// it in a variable with the given name. If the object is not of the
68// expected type call IllegalOperation and return.
69#define CONVERT_CHECKED(Type, name, obj) \
70 RUNTIME_ASSERT(obj->Is##Type()); \
71 Type* name = Type::cast(obj);
72
73#define CONVERT_ARG_CHECKED(Type, name, index) \
74 RUNTIME_ASSERT(args[index]->Is##Type()); \
75 Handle<Type> name = args.at<Type>(index);
76
kasper.lundbd3ec4e2008-07-09 11:06:54 +000077// Cast the given object to a boolean and store it in a variable with
78// the given name. If the object is not a boolean call IllegalOperation
79// and return.
80#define CONVERT_BOOLEAN_CHECKED(name, obj) \
81 RUNTIME_ASSERT(obj->IsBoolean()); \
82 bool name = (obj)->IsTrue();
83
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000084// Cast the given argument to a Smi and store its value in an int variable
85// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000086// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000087#define CONVERT_SMI_ARG_CHECKED(name, index) \
88 RUNTIME_ASSERT(args[index]->IsSmi()); \
89 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000090
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000091// Cast the given argument to a double and store it in a variable with
92// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000093// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000094#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
95 RUNTIME_ASSERT(args[index]->IsNumber()); \
96 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000097
98// Call the specified converter on the object *comand store the result in
99// a variable of the specified type with the given name. If the
100// object is not a Number call IllegalOperation and return.
101#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
102 RUNTIME_ASSERT(obj->IsNumber()); \
103 type name = NumberTo##Type(obj);
104
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000105
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000106MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
107 JSObject* boilerplate) {
108 StackLimitCheck check(isolate);
109 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000110
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000111 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000112 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000113 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000114 if (!maybe_result->ToObject(&result)) return maybe_result;
115 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000116 JSObject* copy = JSObject::cast(result);
117
118 // Deep copy local properties.
119 if (copy->HasFastProperties()) {
120 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000121 for (int i = 0; i < properties->length(); i++) {
122 Object* value = properties->get(i);
123 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000124 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000125 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000126 if (!maybe_result->ToObject(&result)) return maybe_result;
127 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000128 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000129 }
130 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000131 int nof = copy->map()->inobject_properties();
132 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000133 Object* value = copy->InObjectPropertyAt(i);
134 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000135 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000136 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000137 if (!maybe_result->ToObject(&result)) return maybe_result;
138 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000139 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000140 }
141 }
142 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000143 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000144 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000145 if (!maybe_result->ToObject(&result)) return maybe_result;
146 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000147 FixedArray* names = FixedArray::cast(result);
148 copy->GetLocalPropertyNames(names, 0);
149 for (int i = 0; i < names->length(); i++) {
150 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000151 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000152 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000153 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000154 // Only deep copy fields from the object literal expression.
155 // In particular, don't try to copy the length attribute of
156 // an array.
157 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000158 Object* value =
159 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000160 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000161 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000162 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000163 if (!maybe_result->ToObject(&result)) return maybe_result;
164 }
165 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000166 // Creating object copy for literals. No strict mode needed.
167 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000168 if (!maybe_result->ToObject(&result)) return maybe_result;
169 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000170 }
171 }
172 }
173
174 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000175 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000176 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000177 switch (copy->GetElementsKind()) {
178 case JSObject::FAST_ELEMENTS: {
179 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000180 if (elements->map() == heap->fixed_cow_array_map()) {
181 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000182#ifdef DEBUG
183 for (int i = 0; i < elements->length(); i++) {
184 ASSERT(!elements->get(i)->IsJSObject());
185 }
186#endif
187 } else {
188 for (int i = 0; i < elements->length(); i++) {
189 Object* value = elements->get(i);
190 if (value->IsJSObject()) {
191 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000192 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
193 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000194 if (!maybe_result->ToObject(&result)) return maybe_result;
195 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000196 elements->set(i, result);
197 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000198 }
199 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000200 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000201 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000202 case JSObject::DICTIONARY_ELEMENTS: {
203 NumberDictionary* element_dictionary = copy->element_dictionary();
204 int capacity = element_dictionary->Capacity();
205 for (int i = 0; i < capacity; i++) {
206 Object* k = element_dictionary->KeyAt(i);
207 if (element_dictionary->IsKey(k)) {
208 Object* value = element_dictionary->ValueAt(i);
209 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000210 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000211 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
212 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000213 if (!maybe_result->ToObject(&result)) return maybe_result;
214 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000215 element_dictionary->ValueAtPut(i, result);
216 }
217 }
218 }
219 break;
220 }
221 default:
222 UNREACHABLE();
223 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000224 }
225 return copy;
226}
227
228
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000229RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000230 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000231 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000232}
233
234
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000235RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000236 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000237 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000238}
239
240
ager@chromium.org236ad962008-09-25 09:45:57 +0000241static Handle<Map> ComputeObjectLiteralMap(
242 Handle<Context> context,
243 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000244 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000245 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000246 int properties_length = constant_properties->length();
247 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000248 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000249 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000250 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000251 for (int p = 0; p != properties_length; p += 2) {
252 Object* key = constant_properties->get(p);
253 uint32_t element_index = 0;
254 if (key->IsSymbol()) {
255 number_of_symbol_keys++;
256 } else if (key->ToArrayIndex(&element_index)) {
257 // An index key does not require space in the property backing store.
258 number_of_properties--;
259 } else {
260 // Bail out as a non-symbol non-index key makes caching impossible.
261 // ASSERT to make sure that the if condition after the loop is false.
262 ASSERT(number_of_symbol_keys != number_of_properties);
263 break;
264 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000265 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000266 // If we only have symbols and array indices among keys then we can
267 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000268 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000269 if ((number_of_symbol_keys == number_of_properties) &&
270 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000271 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000272 Handle<FixedArray> keys =
273 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000274 if (number_of_symbol_keys > 0) {
275 int index = 0;
276 for (int p = 0; p < properties_length; p += 2) {
277 Object* key = constant_properties->get(p);
278 if (key->IsSymbol()) {
279 keys->set(index++, key);
280 }
281 }
282 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000283 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000284 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000285 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000286 }
287 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000288 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000289 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000290 Handle<Map>(context->object_function()->initial_map()),
291 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000292}
293
294
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000295static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000296 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000297 Handle<FixedArray> literals,
298 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000299
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000300
301static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000302 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000303 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000304 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000305 bool should_have_fast_elements,
306 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000307 // Get the global context from the literals array. This is the
308 // context in which the function was created and we use the object
309 // function from this context to create the object literal. We do
310 // not use the object function from the current global context
311 // because this might be the object function from another context
312 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000313 Handle<Context> context =
314 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
315
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000316 // In case we have function literals, we want the object to be in
317 // slow properties mode for now. We don't go in the map cache because
318 // maps with constant functions can't be shared if the functions are
319 // not the same (which is the common case).
320 bool is_result_from_cache = false;
321 Handle<Map> map = has_function_literal
322 ? Handle<Map>(context->object_function()->initial_map())
323 : ComputeObjectLiteralMap(context,
324 constant_properties,
325 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000326
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000327 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000328
329 // Normalize the elements of the boilerplate to save space if needed.
330 if (!should_have_fast_elements) NormalizeElements(boilerplate);
331
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000332 // Add the constant properties to the boilerplate.
333 int length = constant_properties->length();
334 bool should_transform =
335 !is_result_from_cache && boilerplate->HasFastProperties();
336 if (should_transform || has_function_literal) {
337 // Normalize the properties of object to avoid n^2 behavior
338 // when extending the object multiple properties. Indicate the number of
339 // properties to be added.
340 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
341 }
342
343 for (int index = 0; index < length; index +=2) {
344 Handle<Object> key(constant_properties->get(index+0), isolate);
345 Handle<Object> value(constant_properties->get(index+1), isolate);
346 if (value->IsFixedArray()) {
347 // The value contains the constant_properties of a
348 // simple object or array literal.
349 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
350 value = CreateLiteralBoilerplate(isolate, literals, array);
351 if (value.is_null()) return value;
352 }
353 Handle<Object> result;
354 uint32_t element_index = 0;
355 if (key->IsSymbol()) {
356 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
357 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000358 result = SetOwnElement(boilerplate,
359 element_index,
360 value,
361 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000362 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000363 Handle<String> name(String::cast(*key));
364 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000365 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
366 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000367 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000368 } else if (key->ToArrayIndex(&element_index)) {
369 // Array index (uint32).
370 result = SetOwnElement(boilerplate,
371 element_index,
372 value,
373 kNonStrictMode);
374 } else {
375 // Non-uint32 number.
376 ASSERT(key->IsNumber());
377 double num = key->Number();
378 char arr[100];
379 Vector<char> buffer(arr, ARRAY_SIZE(arr));
380 const char* str = DoubleToCString(num, buffer);
381 Handle<String> name =
382 isolate->factory()->NewStringFromAscii(CStrVector(str));
383 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
384 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000385 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000386 // If setting the property on the boilerplate throws an
387 // exception, the exception is converted to an empty handle in
388 // the handle based operations. In that case, we need to
389 // convert back to an exception.
390 if (result.is_null()) return result;
391 }
392
393 // Transform to fast properties if necessary. For object literals with
394 // containing function literals we defer this operation until after all
395 // computed properties have been assigned so that we can generate
396 // constant function properties.
397 if (should_transform && !has_function_literal) {
398 TransformToFastProperties(boilerplate,
399 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000400 }
401
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000402 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000403}
404
405
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000406static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000407 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000408 Handle<FixedArray> literals,
409 Handle<FixedArray> elements) {
410 // Create the JSArray.
411 Handle<JSFunction> constructor(
412 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000413 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000414
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000415 const bool is_cow =
416 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000417 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000418 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000419
420 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000421 if (is_cow) {
422#ifdef DEBUG
423 // Copy-on-write arrays must be shallow (and simple).
424 for (int i = 0; i < content->length(); i++) {
425 ASSERT(!content->get(i)->IsFixedArray());
426 }
427#endif
428 } else {
429 for (int i = 0; i < content->length(); i++) {
430 if (content->get(i)->IsFixedArray()) {
431 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000432 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000433 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
434 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000435 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000436 if (result.is_null()) return result;
437 content->set(i, *result);
438 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000439 }
440 }
441
442 // Set the elements.
443 Handle<JSArray>::cast(object)->SetContent(*content);
444 return object;
445}
446
447
448static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000449 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000450 Handle<FixedArray> literals,
451 Handle<FixedArray> array) {
452 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000453 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000454 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000455 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000456 return CreateObjectLiteralBoilerplate(isolate,
457 literals,
458 elements,
459 true,
460 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000461 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000462 return CreateObjectLiteralBoilerplate(isolate,
463 literals,
464 elements,
465 false,
466 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000468 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000469 default:
470 UNREACHABLE();
471 return Handle<Object>::null();
472 }
473}
474
475
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000476RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000477 // Takes a FixedArray of elements containing the literal elements of
478 // the array literal and produces JSArray with those elements.
479 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000480 // which contains the context from which to get the Array function
481 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000482 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000483 ASSERT(args.length() == 3);
484 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000485 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000486 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000487
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000488 Handle<Object> object =
489 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000490 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000491
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000492 // Update the functions literal and return the boilerplate.
493 literals->set(literals_index, *object);
494 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000495}
496
497
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000498RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000499 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000500 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000501 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000502 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000503 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000504 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000505 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
506 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000507
508 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000509 Handle<Object> boilerplate(literals->get(literals_index), isolate);
510 if (*boilerplate == isolate->heap()->undefined_value()) {
511 boilerplate = CreateObjectLiteralBoilerplate(isolate,
512 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000513 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000514 should_have_fast_elements,
515 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000516 if (boilerplate.is_null()) return Failure::Exception();
517 // Update the functions literal and return the boilerplate.
518 literals->set(literals_index, *boilerplate);
519 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000520 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000521}
522
523
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000524RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000525 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000526 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000527 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000528 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000529 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000530 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000531 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
532 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000533
534 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000535 Handle<Object> boilerplate(literals->get(literals_index), isolate);
536 if (*boilerplate == isolate->heap()->undefined_value()) {
537 boilerplate = CreateObjectLiteralBoilerplate(isolate,
538 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000539 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000540 should_have_fast_elements,
541 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000542 if (boilerplate.is_null()) return Failure::Exception();
543 // Update the functions literal and return the boilerplate.
544 literals->set(literals_index, *boilerplate);
545 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000546 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000547}
548
549
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000550RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000551 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000552 ASSERT(args.length() == 3);
553 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000554 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000555 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
556
557 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000558 Handle<Object> boilerplate(literals->get(literals_index), isolate);
559 if (*boilerplate == isolate->heap()->undefined_value()) {
560 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000561 if (boilerplate.is_null()) return Failure::Exception();
562 // Update the functions literal and return the boilerplate.
563 literals->set(literals_index, *boilerplate);
564 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000565 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000566}
567
568
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000569RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000570 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000571 ASSERT(args.length() == 3);
572 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000573 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000574 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
575
576 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000577 Handle<Object> boilerplate(literals->get(literals_index), isolate);
578 if (*boilerplate == isolate->heap()->undefined_value()) {
579 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000580 if (boilerplate.is_null()) return Failure::Exception();
581 // Update the functions literal and return the boilerplate.
582 literals->set(literals_index, *boilerplate);
583 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000584 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000585 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000586 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000587 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000588 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000589}
590
591
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000592RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
593 ASSERT(args.length() == 2);
594 Object* handler = args[0];
595 Object* prototype = args[1];
596 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000597 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000598 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
599}
600
601
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000602RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
603 ASSERT(args.length() == 1);
604 Object* obj = args[0];
605 return obj->IsJSProxy()
606 ? isolate->heap()->true_value() : isolate->heap()->false_value();
607}
608
609
610RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
611 ASSERT(args.length() == 1);
612 CONVERT_CHECKED(JSProxy, proxy, args[0]);
613 return proxy->handler();
614}
615
616
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000617RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000618 NoHandleAllocation ha;
619 ASSERT(args.length() == 1);
620 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000621 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000622 return JSObject::cast(obj)->class_name();
623}
624
ager@chromium.org7c537e22008-10-16 08:43:32 +0000625
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000626RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
627 NoHandleAllocation ha;
628 ASSERT(args.length() == 1);
629 Object* obj = args[0];
630 obj = obj->GetPrototype();
631 while (obj->IsJSObject() &&
632 JSObject::cast(obj)->map()->is_hidden_prototype()) {
633 obj = obj->GetPrototype();
634 }
635 return obj;
636}
637
638
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000639RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000640 NoHandleAllocation ha;
641 ASSERT(args.length() == 2);
642 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
643 Object* O = args[0];
644 Object* V = args[1];
645 while (true) {
646 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000647 if (prototype->IsNull()) return isolate->heap()->false_value();
648 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000649 V = prototype;
650 }
651}
652
653
ager@chromium.org9085a012009-05-11 19:22:57 +0000654// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000655RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000656 NoHandleAllocation ha;
657 ASSERT(args.length() == 2);
658 CONVERT_CHECKED(JSObject, jsobject, args[0]);
659 CONVERT_CHECKED(JSObject, proto, args[1]);
660
661 // Sanity checks. The old prototype (that we are replacing) could
662 // theoretically be null, but if it is not null then check that we
663 // didn't already install a hidden prototype here.
664 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
665 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
666 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
667
668 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000669 Object* map_or_failure;
670 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
671 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
672 return maybe_map_or_failure;
673 }
674 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000675 Map* new_proto_map = Map::cast(map_or_failure);
676
lrn@chromium.org303ada72010-10-27 09:33:13 +0000677 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
678 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
679 return maybe_map_or_failure;
680 }
681 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000682 Map* new_map = Map::cast(map_or_failure);
683
684 // Set proto's prototype to be the old prototype of the object.
685 new_proto_map->set_prototype(jsobject->GetPrototype());
686 proto->set_map(new_proto_map);
687 new_proto_map->set_is_hidden_prototype();
688
689 // Set the object's prototype to proto.
690 new_map->set_prototype(proto);
691 jsobject->set_map(new_map);
692
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000693 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000694}
695
696
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000697RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000698 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000699 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000700 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000701 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000702}
703
704
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000705// Recursively traverses hidden prototypes if property is not found
706static void GetOwnPropertyImplementation(JSObject* obj,
707 String* name,
708 LookupResult* result) {
709 obj->LocalLookupRealNamedProperty(name, result);
710
711 if (!result->IsProperty()) {
712 Object* proto = obj->GetPrototype();
713 if (proto->IsJSObject() &&
714 JSObject::cast(proto)->map()->is_hidden_prototype())
715 GetOwnPropertyImplementation(JSObject::cast(proto),
716 name, result);
717 }
718}
719
720
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000721static bool CheckAccessException(LookupResult* result,
722 v8::AccessType access_type) {
723 if (result->type() == CALLBACKS) {
724 Object* callback = result->GetCallbackObject();
725 if (callback->IsAccessorInfo()) {
726 AccessorInfo* info = AccessorInfo::cast(callback);
727 bool can_access =
728 (access_type == v8::ACCESS_HAS &&
729 (info->all_can_read() || info->all_can_write())) ||
730 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
731 (access_type == v8::ACCESS_SET && info->all_can_write());
732 return can_access;
733 }
734 }
735
736 return false;
737}
738
739
740static bool CheckAccess(JSObject* obj,
741 String* name,
742 LookupResult* result,
743 v8::AccessType access_type) {
744 ASSERT(result->IsProperty());
745
746 JSObject* holder = result->holder();
747 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000748 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000749 while (true) {
750 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000751 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000752 // Access check callback denied the access, but some properties
753 // can have a special permissions which override callbacks descision
754 // (currently see v8::AccessControl).
755 break;
756 }
757
758 if (current == holder) {
759 return true;
760 }
761
762 current = JSObject::cast(current->GetPrototype());
763 }
764
765 // API callbacks can have per callback access exceptions.
766 switch (result->type()) {
767 case CALLBACKS: {
768 if (CheckAccessException(result, access_type)) {
769 return true;
770 }
771 break;
772 }
773 case INTERCEPTOR: {
774 // If the object has an interceptor, try real named properties.
775 // Overwrite the result to fetch the correct property later.
776 holder->LookupRealNamedProperty(name, result);
777 if (result->IsProperty()) {
778 if (CheckAccessException(result, access_type)) {
779 return true;
780 }
781 }
782 break;
783 }
784 default:
785 break;
786 }
787
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000788 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000789 return false;
790}
791
792
793// TODO(1095): we should traverse hidden prototype hierachy as well.
794static bool CheckElementAccess(JSObject* obj,
795 uint32_t index,
796 v8::AccessType access_type) {
797 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000798 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000799 return false;
800 }
801
802 return true;
803}
804
805
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000806// Enumerator used as indices into the array returned from GetOwnProperty
807enum PropertyDescriptorIndices {
808 IS_ACCESSOR_INDEX,
809 VALUE_INDEX,
810 GETTER_INDEX,
811 SETTER_INDEX,
812 WRITABLE_INDEX,
813 ENUMERABLE_INDEX,
814 CONFIGURABLE_INDEX,
815 DESCRIPTOR_SIZE
816};
817
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000818// Returns an array with the property description:
819// if args[1] is not a property on args[0]
820// returns undefined
821// if args[1] is a data property on args[0]
822// [false, value, Writeable, Enumerable, Configurable]
823// if args[1] is an accessor on args[0]
824// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000825RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000826 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000827 Heap* heap = isolate->heap();
828 HandleScope scope(isolate);
829 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
830 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000831 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000832 CONVERT_ARG_CHECKED(JSObject, obj, 0);
833 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000834
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000835 // This could be an element.
836 uint32_t index;
837 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000838 switch (obj->HasLocalElement(index)) {
839 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000840 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000841
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000842 case JSObject::STRING_CHARACTER_ELEMENT: {
843 // Special handling of string objects according to ECMAScript 5
844 // 15.5.5.2. Note that this might be a string object with elements
845 // other than the actual string value. This is covered by the
846 // subsequent cases.
847 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
848 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000849 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000850
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000851 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000852 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000853 elms->set(WRITABLE_INDEX, heap->false_value());
854 elms->set(ENUMERABLE_INDEX, heap->false_value());
855 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000856 return *desc;
857 }
858
859 case JSObject::INTERCEPTED_ELEMENT:
860 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000861 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000862 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000863 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000864 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000865 elms->set(WRITABLE_INDEX, heap->true_value());
866 elms->set(ENUMERABLE_INDEX, heap->true_value());
867 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000868 return *desc;
869 }
870
871 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000872 Handle<JSObject> holder = obj;
873 if (obj->IsJSGlobalProxy()) {
874 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000875 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000876 ASSERT(proto->IsJSGlobalObject());
877 holder = Handle<JSObject>(JSObject::cast(proto));
878 }
879 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000880 int entry = dictionary->FindEntry(index);
881 ASSERT(entry != NumberDictionary::kNotFound);
882 PropertyDetails details = dictionary->DetailsAt(entry);
883 switch (details.type()) {
884 case CALLBACKS: {
885 // This is an accessor property with getter and/or setter.
886 FixedArray* callbacks =
887 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000888 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000889 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
890 elms->set(GETTER_INDEX, callbacks->get(0));
891 }
892 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
893 elms->set(SETTER_INDEX, callbacks->get(1));
894 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000895 break;
896 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000897 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000898 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000899 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000900 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000901 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000902 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000903 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000904 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000905 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000906 default:
907 UNREACHABLE();
908 break;
909 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000910 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
911 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000912 return *desc;
913 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000914 }
915 }
916
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000917 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000918 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000919
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000920 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000921 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000922 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000923
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000924 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000925 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000926 }
927
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000928 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
929 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000930
931 bool is_js_accessor = (result.type() == CALLBACKS) &&
932 (result.GetCallbackObject()->IsFixedArray());
933
934 if (is_js_accessor) {
935 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000936 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000937
938 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
939 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
940 elms->set(GETTER_INDEX, structure->get(0));
941 }
942 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
943 elms->set(SETTER_INDEX, structure->get(1));
944 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000945 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000946 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
947 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000948
949 PropertyAttributes attrs;
950 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000951 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000952 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
953 if (!maybe_value->ToObject(&value)) return maybe_value;
954 }
955 elms->set(VALUE_INDEX, value);
956 }
957
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000958 return *desc;
959}
960
961
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000962RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000963 ASSERT(args.length() == 1);
964 CONVERT_CHECKED(JSObject, obj, args[0]);
965 return obj->PreventExtensions();
966}
967
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000968
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000969RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000970 ASSERT(args.length() == 1);
971 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000972 if (obj->IsJSGlobalProxy()) {
973 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000974 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000975 ASSERT(proto->IsJSGlobalObject());
976 obj = JSObject::cast(proto);
977 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000978 return obj->map()->is_extensible() ? isolate->heap()->true_value()
979 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000980}
981
982
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000983RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000984 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000985 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000986 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
987 CONVERT_ARG_CHECKED(String, pattern, 1);
988 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000989 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
990 if (result.is_null()) return Failure::Exception();
991 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000992}
993
994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000995RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000996 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000998 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000999 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001000}
1001
1002
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001003RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001004 ASSERT(args.length() == 1);
1005 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001006 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001007 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001008}
1009
1010
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001011RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001012 ASSERT(args.length() == 2);
1013 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001014 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001015 int index = field->value();
1016 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1017 InstanceType type = templ->map()->instance_type();
1018 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1019 type == OBJECT_TEMPLATE_INFO_TYPE);
1020 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001021 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001022 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1023 } else {
1024 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1025 }
1026 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001027}
1028
1029
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001030RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001031 ASSERT(args.length() == 1);
1032 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001033 Map* old_map = object->map();
1034 bool needs_access_checks = old_map->is_access_check_needed();
1035 if (needs_access_checks) {
1036 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001037 Object* new_map;
1038 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1039 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1040 }
ager@chromium.org32912102009-01-16 10:38:43 +00001041
1042 Map::cast(new_map)->set_is_access_check_needed(false);
1043 object->set_map(Map::cast(new_map));
1044 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001045 return needs_access_checks ? isolate->heap()->true_value()
1046 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001047}
1048
1049
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001050RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001051 ASSERT(args.length() == 1);
1052 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001053 Map* old_map = object->map();
1054 if (!old_map->is_access_check_needed()) {
1055 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001056 Object* new_map;
1057 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1058 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1059 }
ager@chromium.org32912102009-01-16 10:38:43 +00001060
1061 Map::cast(new_map)->set_is_access_check_needed(true);
1062 object->set_map(Map::cast(new_map));
1063 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001064 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001065}
1066
1067
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001068static Failure* ThrowRedeclarationError(Isolate* isolate,
1069 const char* type,
1070 Handle<String> name) {
1071 HandleScope scope(isolate);
1072 Handle<Object> type_handle =
1073 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001074 Handle<Object> args[2] = { type_handle, name };
1075 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001076 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1077 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001078}
1079
1080
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001081RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001082 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001083 HandleScope scope(isolate);
1084 Handle<GlobalObject> global = Handle<GlobalObject>(
1085 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001086
ager@chromium.org3811b432009-10-28 14:53:37 +00001087 Handle<Context> context = args.at<Context>(0);
1088 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001089 bool is_eval = args.smi_at(2) == 1;
1090 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001091 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001092
1093 // Compute the property attributes. According to ECMA-262, section
1094 // 13, page 71, the property must be read-only and
1095 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1096 // property as read-only, so we don't either.
1097 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1098
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001099 // Traverse the name/value pairs and set the properties.
1100 int length = pairs->length();
1101 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001102 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001103 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001104 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001105
1106 // We have to declare a global const property. To capture we only
1107 // assign to it when evaluating the assignment for "const x =
1108 // <expr>" the initial value is the hole.
1109 bool is_const_property = value->IsTheHole();
1110
1111 if (value->IsUndefined() || is_const_property) {
1112 // Lookup the property in the global object, and don't set the
1113 // value of the variable if the property is already there.
1114 LookupResult lookup;
1115 global->Lookup(*name, &lookup);
1116 if (lookup.IsProperty()) {
1117 // Determine if the property is local by comparing the holder
1118 // against the global object. The information will be used to
1119 // avoid throwing re-declaration errors when declaring
1120 // variables or constants that exist in the prototype chain.
1121 bool is_local = (*global == lookup.holder());
1122 // Get the property attributes and determine if the property is
1123 // read-only.
1124 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1125 bool is_read_only = (attributes & READ_ONLY) != 0;
1126 if (lookup.type() == INTERCEPTOR) {
1127 // If the interceptor says the property is there, we
1128 // just return undefined without overwriting the property.
1129 // Otherwise, we continue to setting the property.
1130 if (attributes != ABSENT) {
1131 // Check if the existing property conflicts with regards to const.
1132 if (is_local && (is_read_only || is_const_property)) {
1133 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001134 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001135 };
1136 // The property already exists without conflicting: Go to
1137 // the next declaration.
1138 continue;
1139 }
1140 // Fall-through and introduce the absent property by using
1141 // SetProperty.
1142 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001143 // For const properties, we treat a callback with this name
1144 // even in the prototype as a conflicting declaration.
1145 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001146 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001147 }
1148 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001149 if (is_local && (is_read_only || is_const_property)) {
1150 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001151 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001152 }
1153 // The property already exists without conflicting: Go to
1154 // the next declaration.
1155 continue;
1156 }
1157 }
1158 } else {
1159 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001160 Handle<SharedFunctionInfo> shared =
1161 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001162 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001163 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1164 context,
1165 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001166 value = function;
1167 }
1168
1169 LookupResult lookup;
1170 global->LocalLookup(*name, &lookup);
1171
1172 PropertyAttributes attributes = is_const_property
1173 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1174 : base;
1175
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001176 // There's a local property that we need to overwrite because
1177 // we're either declaring a function or there's an interceptor
1178 // that claims the property is absent.
1179 //
1180 // Check for conflicting re-declarations. We cannot have
1181 // conflicting types in case of intercepted properties because
1182 // they are absent.
1183 if (lookup.IsProperty() &&
1184 (lookup.type() != INTERCEPTOR) &&
1185 (lookup.IsReadOnly() || is_const_property)) {
1186 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001187 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001188 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001189
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001190 // Safari does not allow the invocation of callback setters for
1191 // function declarations. To mimic this behavior, we do not allow
1192 // the invocation of setters for function values. This makes a
1193 // difference for global functions with the same names as event
1194 // handlers such as "function onload() {}". Firefox does call the
1195 // onload setter in those case and Safari does not. We follow
1196 // Safari for compatibility.
1197 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001198 // Do not change DONT_DELETE to false from true.
1199 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1200 attributes = static_cast<PropertyAttributes>(
1201 attributes | (lookup.GetAttributes() & DONT_DELETE));
1202 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001203 RETURN_IF_EMPTY_HANDLE(isolate,
1204 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001205 name,
1206 value,
1207 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001208 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001209 RETURN_IF_EMPTY_HANDLE(isolate,
1210 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001211 name,
1212 value,
1213 attributes,
1214 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215 }
1216 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001217
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001218 ASSERT(!isolate->has_pending_exception());
1219 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001220}
1221
1222
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001223RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001224 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001225 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226
ager@chromium.org7c537e22008-10-16 08:43:32 +00001227 CONVERT_ARG_CHECKED(Context, context, 0);
1228 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001229 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001230 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001231 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001232
1233 // Declarations are always done in the function context.
1234 context = Handle<Context>(context->fcontext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001235 ASSERT(context->IsFunctionContext() || context->IsGlobalContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001236
1237 int index;
1238 PropertyAttributes attributes;
1239 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001240 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001241 context->Lookup(name, flags, &index, &attributes);
1242
1243 if (attributes != ABSENT) {
1244 // The name was declared before; check for conflicting
1245 // re-declarations: This is similar to the code in parser.cc in
1246 // the AstBuildingParser::Declare function.
1247 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1248 // Functions are not read-only.
1249 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1250 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001251 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001252 }
1253
1254 // Initialize it if necessary.
1255 if (*initial_value != NULL) {
1256 if (index >= 0) {
1257 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001258 // the function context or the arguments object.
1259 if (holder->IsContext()) {
1260 ASSERT(holder.is_identical_to(context));
1261 if (((attributes & READ_ONLY) == 0) ||
1262 context->get(index)->IsTheHole()) {
1263 context->set(index, *initial_value);
1264 }
1265 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001266 // The holder is an arguments object.
1267 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001268 Handle<Object> result = SetElement(arguments, index, initial_value,
1269 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001270 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001271 }
1272 } else {
1273 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001274 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001275 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001276 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001277 SetProperty(context_ext, name, initial_value,
1278 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001279 }
1280 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001283 // The property is not in the function context. It needs to be
1284 // "declared" in the function context's extension context, or in the
1285 // global context.
1286 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001287 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001288 // The function context's extension context exists - use it.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001289 context_ext = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001290 } else {
1291 // The function context's extension context does not exists - allocate
1292 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001293 context_ext = isolate->factory()->NewJSObject(
1294 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001295 // And store it in the extension slot.
1296 context->set_extension(*context_ext);
1297 }
1298 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001299
ager@chromium.org7c537e22008-10-16 08:43:32 +00001300 // Declare the property by setting it to the initial value if provided,
1301 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1302 // constant declarations).
1303 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001304 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001305 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001306 // Declaring a const context slot is a conflicting declaration if
1307 // there is a callback with that name in a prototype. It is
1308 // allowed to introduce const variables in
1309 // JSContextExtensionObjects. They are treated specially in
1310 // SetProperty and no setters are invoked for those since they are
1311 // not real JSObjects.
1312 if (initial_value->IsTheHole() &&
1313 !context_ext->IsJSContextExtensionObject()) {
1314 LookupResult lookup;
1315 context_ext->Lookup(*name, &lookup);
1316 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001317 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001318 }
1319 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001320 RETURN_IF_EMPTY_HANDLE(isolate,
1321 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001322 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001323 }
1324
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001325 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001326}
1327
1328
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001329RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001330 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001331 // args[0] == name
1332 // args[1] == strict_mode
1333 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001334
1335 // Determine if we need to assign to the variable if it already
1336 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001337 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1338 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001339
1340 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001341 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001342 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001343 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001344 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345
1346 // According to ECMA-262, section 12.2, page 62, the property must
1347 // not be deletable.
1348 PropertyAttributes attributes = DONT_DELETE;
1349
1350 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001351 // there, there is a property with this name in the prototype chain.
1352 // We follow Safari and Firefox behavior and only set the property
1353 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001354 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001355 // Note that objects can have hidden prototypes, so we need to traverse
1356 // the whole chain of hidden prototypes to do a 'local' lookup.
1357 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001359 while (true) {
1360 real_holder->LocalLookup(*name, &lookup);
1361 if (lookup.IsProperty()) {
1362 // Determine if this is a redeclaration of something read-only.
1363 if (lookup.IsReadOnly()) {
1364 // If we found readonly property on one of hidden prototypes,
1365 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001366 if (real_holder != isolate->context()->global()) break;
1367 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001368 }
1369
1370 // Determine if this is a redeclaration of an intercepted read-only
1371 // property and figure out if the property exists at all.
1372 bool found = true;
1373 PropertyType type = lookup.type();
1374 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001375 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001376 Handle<JSObject> holder(real_holder);
1377 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1378 real_holder = *holder;
1379 if (intercepted == ABSENT) {
1380 // The interceptor claims the property isn't there. We need to
1381 // make sure to introduce it.
1382 found = false;
1383 } else if ((intercepted & READ_ONLY) != 0) {
1384 // The property is present, but read-only. Since we're trying to
1385 // overwrite it with a variable declaration we must throw a
1386 // re-declaration error. However if we found readonly property
1387 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001388 if (real_holder != isolate->context()->global()) break;
1389 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001390 }
1391 }
1392
1393 if (found && !assign) {
1394 // The global property is there and we're not assigning any value
1395 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001396 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001397 }
1398
1399 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001400 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001401 return real_holder->SetProperty(
1402 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001403 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001404
1405 Object* proto = real_holder->GetPrototype();
1406 if (!proto->IsJSObject())
1407 break;
1408
1409 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1410 break;
1411
1412 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001413 }
1414
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001415 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001416 if (assign) {
1417 return global->SetProperty(*name, args[2], attributes, strict_mode);
1418 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001419 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001420}
1421
1422
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001423RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001424 // All constants are declared with an initial value. The name
1425 // of the constant is the first argument and the initial value
1426 // is the second.
1427 RUNTIME_ASSERT(args.length() == 2);
1428 CONVERT_ARG_CHECKED(String, name, 0);
1429 Handle<Object> value = args.at<Object>(1);
1430
1431 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001432 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001433
1434 // According to ECMA-262, section 12.2, page 62, the property must
1435 // not be deletable. Since it's a const, it must be READ_ONLY too.
1436 PropertyAttributes attributes =
1437 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1438
1439 // Lookup the property locally in the global object. If it isn't
1440 // there, we add the property and take special precautions to always
1441 // add it as a local property even in case of callbacks in the
1442 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001443 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001444 LookupResult lookup;
1445 global->LocalLookup(*name, &lookup);
1446 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001447 return global->SetLocalPropertyIgnoreAttributes(*name,
1448 *value,
1449 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001450 }
1451
1452 // Determine if this is a redeclaration of something not
1453 // read-only. In case the result is hidden behind an interceptor we
1454 // need to ask it for the property attributes.
1455 if (!lookup.IsReadOnly()) {
1456 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001457 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001458 }
1459
1460 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1461
1462 // Throw re-declaration error if the intercepted property is present
1463 // but not read-only.
1464 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001465 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001466 }
1467
1468 // Restore global object from context (in case of GC) and continue
1469 // with setting the value because the property is either absent or
1470 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001471 HandleScope handle_scope(isolate);
1472 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001473
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001474 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001475 // property through an interceptor and only do it if it's
1476 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001477 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001478 RETURN_IF_EMPTY_HANDLE(isolate,
1479 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001480 name,
1481 value,
1482 attributes,
1483 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001484 return *value;
1485 }
1486
1487 // Set the value, but only we're assigning the initial value to a
1488 // constant. For now, we determine this by checking if the
1489 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001490 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001491 PropertyType type = lookup.type();
1492 if (type == FIELD) {
1493 FixedArray* properties = global->properties();
1494 int index = lookup.GetFieldIndex();
1495 if (properties->get(index)->IsTheHole()) {
1496 properties->set(index, *value);
1497 }
1498 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001499 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1500 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001501 }
1502 } else {
1503 // Ignore re-initialization of constants that have already been
1504 // assigned a function value.
1505 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1506 }
1507
1508 // Use the set value as the result of the operation.
1509 return *value;
1510}
1511
1512
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001513RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001514 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515 ASSERT(args.length() == 3);
1516
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001517 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001518 ASSERT(!value->IsTheHole());
1519 CONVERT_ARG_CHECKED(Context, context, 1);
1520 Handle<String> name(String::cast(args[2]));
1521
1522 // Initializations are always done in the function context.
1523 context = Handle<Context>(context->fcontext());
1524
1525 int index;
1526 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001527 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001528 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001529 context->Lookup(name, flags, &index, &attributes);
1530
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001531 // In most situations, the property introduced by the const
1532 // declaration should be present in the context extension object.
1533 // However, because declaration and initialization are separate, the
1534 // property might have been deleted (if it was introduced by eval)
1535 // before we reach the initialization point.
1536 //
1537 // Example:
1538 //
1539 // function f() { eval("delete x; const x;"); }
1540 //
1541 // In that case, the initialization behaves like a normal assignment
1542 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001544 // Property was found in a context.
1545 if (holder->IsContext()) {
1546 // The holder cannot be the function context. If it is, there
1547 // should have been a const redeclaration error when declaring
1548 // the const property.
1549 ASSERT(!holder.is_identical_to(context));
1550 if ((attributes & READ_ONLY) == 0) {
1551 Handle<Context>::cast(holder)->set(index, *value);
1552 }
1553 } else {
1554 // The holder is an arguments object.
1555 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001556 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001557 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001558 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001559 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560 }
1561 return *value;
1562 }
1563
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001564 // The property could not be found, we introduce it in the global
1565 // context.
1566 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001567 Handle<JSObject> global = Handle<JSObject>(
1568 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001569 // Strict mode not needed (const disallowed in strict mode).
1570 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001571 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001572 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001573 return *value;
1574 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001575
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001576 // The property was present in a context extension object.
1577 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001578
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001579 if (*context_ext == context->extension()) {
1580 // This is the property that was introduced by the const
1581 // declaration. Set it if it hasn't been set before. NOTE: We
1582 // cannot use GetProperty() to get the current value as it
1583 // 'unholes' the value.
1584 LookupResult lookup;
1585 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1586 ASSERT(lookup.IsProperty()); // the property was declared
1587 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1588
1589 PropertyType type = lookup.type();
1590 if (type == FIELD) {
1591 FixedArray* properties = context_ext->properties();
1592 int index = lookup.GetFieldIndex();
1593 if (properties->get(index)->IsTheHole()) {
1594 properties->set(index, *value);
1595 }
1596 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001597 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1598 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001599 }
1600 } else {
1601 // We should not reach here. Any real, named property should be
1602 // either a field or a dictionary slot.
1603 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001604 }
1605 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001606 // The property was found in a different context extension object.
1607 // Set it if it is not a read-only property.
1608 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001609 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001610 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001611 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001612 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001613 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001614 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001615
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001616 return *value;
1617}
1618
1619
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001620RUNTIME_FUNCTION(MaybeObject*,
1621 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001622 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001623 ASSERT(args.length() == 2);
1624 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001625 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001626 if (object->HasFastProperties()) {
1627 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1628 }
1629 return *object;
1630}
1631
1632
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001633RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001634 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001635 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001636 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1637 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001638 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001639 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001640 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001641 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001642 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001643 RUNTIME_ASSERT(index >= 0);
1644 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001645 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001646 Handle<Object> result = RegExpImpl::Exec(regexp,
1647 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001648 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001649 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001650 if (result.is_null()) return Failure::Exception();
1651 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001652}
1653
1654
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001655RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001656 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001657 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001658 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001659 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001660 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001661 Object* new_object;
1662 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001663 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001664 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1665 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001666 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001667 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1668 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001669 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1670 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001671 {
1672 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001673 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001674 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001675 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001676 }
1677 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001678 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001679 array->set_elements(elements);
1680 array->set_length(Smi::FromInt(elements_count));
1681 // Write in-object properties after the length of the array.
1682 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1683 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1684 return array;
1685}
1686
1687
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001688RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001689 AssertNoAllocation no_alloc;
1690 ASSERT(args.length() == 5);
1691 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1692 CONVERT_CHECKED(String, source, args[1]);
1693
1694 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001695 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001696
1697 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001698 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001699
1700 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001701 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001702
1703 Map* map = regexp->map();
1704 Object* constructor = map->constructor();
1705 if (constructor->IsJSFunction() &&
1706 JSFunction::cast(constructor)->initial_map() == map) {
1707 // If we still have the original map, set in-object properties directly.
1708 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1709 // TODO(lrn): Consider skipping write barrier on booleans as well.
1710 // Both true and false should be in oldspace at all times.
1711 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1712 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1713 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1714 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1715 Smi::FromInt(0),
1716 SKIP_WRITE_BARRIER);
1717 return regexp;
1718 }
1719
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001720 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001721 PropertyAttributes final =
1722 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1723 PropertyAttributes writable =
1724 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001725 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001726 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001727 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001728 source,
1729 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001730 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001732 global,
1733 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001734 ASSERT(!result->IsFailure());
1735 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001736 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001737 ignoreCase,
1738 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001739 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001740 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001741 multiline,
1742 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001743 ASSERT(!result->IsFailure());
1744 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001745 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001746 Smi::FromInt(0),
1747 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001748 ASSERT(!result->IsFailure());
1749 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001750 return regexp;
1751}
1752
1753
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001754RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001755 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001756 ASSERT(args.length() == 1);
1757 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1758 // This is necessary to enable fast checks for absence of elements
1759 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001760 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001761 return Smi::FromInt(0);
1762}
1763
1764
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001765static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1766 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001767 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001768 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001769 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1770 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1771 Handle<JSFunction> optimized =
1772 isolate->factory()->NewFunction(key,
1773 JS_OBJECT_TYPE,
1774 JSObject::kHeaderSize,
1775 code,
1776 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001777 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001778 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001779 return optimized;
1780}
1781
1782
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001783RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001784 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001785 ASSERT(args.length() == 1);
1786 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1787
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001788 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1789 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1790 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1791 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1792 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1793 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1794 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001795
1796 return *holder;
1797}
1798
1799
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001800RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001801 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001802 Context* global_context =
1803 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001804 return global_context->global()->global_receiver();
1805}
1806
1807
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001808RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001809 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001810 ASSERT(args.length() == 4);
1811 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001812 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001813 Handle<String> pattern = args.at<String>(2);
1814 Handle<String> flags = args.at<String>(3);
1815
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001816 // Get the RegExp function from the context in the literals array.
1817 // This is the RegExp function from the context in which the
1818 // function was created. We do not use the RegExp function from the
1819 // current global context because this might be the RegExp function
1820 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001821 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001822 Handle<JSFunction>(
1823 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001824 // Compute the regular expression literal.
1825 bool has_pending_exception;
1826 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001827 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1828 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001829 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001830 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001831 return Failure::Exception();
1832 }
1833 literals->set(index, *regexp);
1834 return *regexp;
1835}
1836
1837
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001838RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001839 NoHandleAllocation ha;
1840 ASSERT(args.length() == 1);
1841
1842 CONVERT_CHECKED(JSFunction, f, args[0]);
1843 return f->shared()->name();
1844}
1845
1846
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001847RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001848 NoHandleAllocation ha;
1849 ASSERT(args.length() == 2);
1850
1851 CONVERT_CHECKED(JSFunction, f, args[0]);
1852 CONVERT_CHECKED(String, name, args[1]);
1853 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001854 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001855}
1856
1857
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001858RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001859 NoHandleAllocation ha;
1860 ASSERT(args.length() == 1);
1861
1862 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001863 Object* obj = f->RemovePrototype();
1864 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001865
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001866 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001867}
1868
1869
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001870RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001871 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001872 ASSERT(args.length() == 1);
1873
1874 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001875 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1876 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001877
1878 return *GetScriptWrapper(Handle<Script>::cast(script));
1879}
1880
1881
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001882RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001883 NoHandleAllocation ha;
1884 ASSERT(args.length() == 1);
1885
1886 CONVERT_CHECKED(JSFunction, f, args[0]);
1887 return f->shared()->GetSourceCode();
1888}
1889
1890
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001891RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001892 NoHandleAllocation ha;
1893 ASSERT(args.length() == 1);
1894
1895 CONVERT_CHECKED(JSFunction, fun, args[0]);
1896 int pos = fun->shared()->start_position();
1897 return Smi::FromInt(pos);
1898}
1899
1900
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001901RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001902 ASSERT(args.length() == 2);
1903
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001904 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001905 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1906
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001907 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1908
1909 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001910 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001911}
1912
1913
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001914RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001915 NoHandleAllocation ha;
1916 ASSERT(args.length() == 2);
1917
1918 CONVERT_CHECKED(JSFunction, fun, args[0]);
1919 CONVERT_CHECKED(String, name, args[1]);
1920 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001921 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001922}
1923
1924
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001925RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001926 NoHandleAllocation ha;
1927 ASSERT(args.length() == 2);
1928
1929 CONVERT_CHECKED(JSFunction, fun, args[0]);
1930 CONVERT_CHECKED(Smi, length, args[1]);
1931 fun->shared()->set_length(length->value());
1932 return length;
1933}
1934
1935
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001936RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001937 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001938 ASSERT(args.length() == 2);
1939
1940 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001941 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001942 Object* obj;
1943 { MaybeObject* maybe_obj =
1944 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1945 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1946 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001947 return args[0]; // return TOS
1948}
1949
1950
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001951RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001952 NoHandleAllocation ha;
1953 ASSERT(args.length() == 1);
1954
1955 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001956 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1957 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001958}
1959
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001960
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001961RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001962 NoHandleAllocation ha;
1963 ASSERT(args.length() == 1);
1964
1965 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001966 return f->IsBuiltin() ? isolate->heap()->true_value() :
1967 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001968}
1969
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001970
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001971RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001972 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001973 ASSERT(args.length() == 2);
1974
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001975 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001976 Handle<Object> code = args.at<Object>(1);
1977
1978 Handle<Context> context(target->context());
1979
1980 if (!code->IsNull()) {
1981 RUNTIME_ASSERT(code->IsJSFunction());
1982 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001983 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001984
1985 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001986 return Failure::Exception();
1987 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001988 // Since we don't store the source for this we should never
1989 // optimize this.
1990 shared->code()->set_optimizable(false);
1991
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001992 // Set the code, scope info, formal parameter count,
1993 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001994 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001995 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001996 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001997 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001998 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001999 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002000 // Set the source code of the target function to undefined.
2001 // SetCode is only used for built-in constructors like String,
2002 // Array, and Object, and some web code
2003 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002004 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002005 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002006 // Clear the optimization hints related to the compiled code as these are no
2007 // longer valid when the code is overwritten.
2008 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002009 context = Handle<Context>(fun->context());
2010
2011 // Make sure we get a fresh copy of the literal vector to avoid
2012 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002013 int number_of_literals = fun->NumberOfLiterals();
2014 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002015 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002016 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002017 // Insert the object, regexp and array functions in the literals
2018 // array prefix. These are the functions that will be used when
2019 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002020 literals->set(JSFunction::kLiteralGlobalContextIndex,
2021 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002022 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002023 // It's okay to skip the write barrier here because the literals
2024 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002025 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002026 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002027 }
2028
2029 target->set_context(*context);
2030 return *target;
2031}
2032
2033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002034RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002035 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002036 ASSERT(args.length() == 2);
2037 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002038 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002039 RUNTIME_ASSERT(num >= 0);
2040 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002041 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002042}
2043
2044
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002045MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2046 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002047 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002048 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002049 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002050 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002051 }
2052 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002053 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002054}
2055
2056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002057RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002058 NoHandleAllocation ha;
2059 ASSERT(args.length() == 2);
2060
2061 CONVERT_CHECKED(String, subject, args[0]);
2062 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002063 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002064
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002065 uint32_t i = 0;
2066 if (index->IsSmi()) {
2067 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002068 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002069 i = value;
2070 } else {
2071 ASSERT(index->IsHeapNumber());
2072 double value = HeapNumber::cast(index)->value();
2073 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002074 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002075
2076 // Flatten the string. If someone wants to get a char at an index
2077 // in a cons string, it is likely that more indices will be
2078 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002079 Object* flat;
2080 { MaybeObject* maybe_flat = subject->TryFlatten();
2081 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2082 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002083 subject = String::cast(flat);
2084
2085 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002086 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002087 }
2088
2089 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002090}
2091
2092
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002093RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002094 NoHandleAllocation ha;
2095 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002096 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002097}
2098
lrn@chromium.org25156de2010-04-06 13:10:27 +00002099
2100class FixedArrayBuilder {
2101 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002102 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2103 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002104 length_(0) {
2105 // Require a non-zero initial size. Ensures that doubling the size to
2106 // extend the array will work.
2107 ASSERT(initial_capacity > 0);
2108 }
2109
2110 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2111 : array_(backing_store),
2112 length_(0) {
2113 // Require a non-zero initial size. Ensures that doubling the size to
2114 // extend the array will work.
2115 ASSERT(backing_store->length() > 0);
2116 }
2117
2118 bool HasCapacity(int elements) {
2119 int length = array_->length();
2120 int required_length = length_ + elements;
2121 return (length >= required_length);
2122 }
2123
2124 void EnsureCapacity(int elements) {
2125 int length = array_->length();
2126 int required_length = length_ + elements;
2127 if (length < required_length) {
2128 int new_length = length;
2129 do {
2130 new_length *= 2;
2131 } while (new_length < required_length);
2132 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002133 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002134 array_->CopyTo(0, *extended_array, 0, length_);
2135 array_ = extended_array;
2136 }
2137 }
2138
2139 void Add(Object* value) {
2140 ASSERT(length_ < capacity());
2141 array_->set(length_, value);
2142 length_++;
2143 }
2144
2145 void Add(Smi* value) {
2146 ASSERT(length_ < capacity());
2147 array_->set(length_, value);
2148 length_++;
2149 }
2150
2151 Handle<FixedArray> array() {
2152 return array_;
2153 }
2154
2155 int length() {
2156 return length_;
2157 }
2158
2159 int capacity() {
2160 return array_->length();
2161 }
2162
2163 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002164 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002165 result_array->set_length(Smi::FromInt(length_));
2166 return result_array;
2167 }
2168
2169 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2170 target_array->set_elements(*array_);
2171 target_array->set_length(Smi::FromInt(length_));
2172 return target_array;
2173 }
2174
2175 private:
2176 Handle<FixedArray> array_;
2177 int length_;
2178};
2179
2180
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002181// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002182const int kStringBuilderConcatHelperLengthBits = 11;
2183const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002184
2185template <typename schar>
2186static inline void StringBuilderConcatHelper(String*,
2187 schar*,
2188 FixedArray*,
2189 int);
2190
lrn@chromium.org25156de2010-04-06 13:10:27 +00002191typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2192 StringBuilderSubstringLength;
2193typedef BitField<int,
2194 kStringBuilderConcatHelperLengthBits,
2195 kStringBuilderConcatHelperPositionBits>
2196 StringBuilderSubstringPosition;
2197
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002198
2199class ReplacementStringBuilder {
2200 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002201 ReplacementStringBuilder(Heap* heap,
2202 Handle<String> subject,
2203 int estimated_part_count)
2204 : heap_(heap),
2205 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002206 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002207 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002208 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002209 // Require a non-zero initial size. Ensures that doubling the size to
2210 // extend the array will work.
2211 ASSERT(estimated_part_count > 0);
2212 }
2213
lrn@chromium.org25156de2010-04-06 13:10:27 +00002214 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2215 int from,
2216 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002217 ASSERT(from >= 0);
2218 int length = to - from;
2219 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002220 if (StringBuilderSubstringLength::is_valid(length) &&
2221 StringBuilderSubstringPosition::is_valid(from)) {
2222 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2223 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002224 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002225 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002226 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002227 builder->Add(Smi::FromInt(-length));
2228 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002229 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002230 }
2231
2232
2233 void EnsureCapacity(int elements) {
2234 array_builder_.EnsureCapacity(elements);
2235 }
2236
2237
2238 void AddSubjectSlice(int from, int to) {
2239 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002240 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002241 }
2242
2243
2244 void AddString(Handle<String> string) {
2245 int length = string->length();
2246 ASSERT(length > 0);
2247 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002248 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002249 is_ascii_ = false;
2250 }
2251 IncrementCharacterCount(length);
2252 }
2253
2254
2255 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002256 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002257 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002258 }
2259
2260 Handle<String> joined_string;
2261 if (is_ascii_) {
2262 joined_string = NewRawAsciiString(character_count_);
2263 AssertNoAllocation no_alloc;
2264 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2265 char* char_buffer = seq->GetChars();
2266 StringBuilderConcatHelper(*subject_,
2267 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002268 *array_builder_.array(),
2269 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002270 } else {
2271 // Non-ASCII.
2272 joined_string = NewRawTwoByteString(character_count_);
2273 AssertNoAllocation no_alloc;
2274 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2275 uc16* char_buffer = seq->GetChars();
2276 StringBuilderConcatHelper(*subject_,
2277 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002278 *array_builder_.array(),
2279 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002280 }
2281 return joined_string;
2282 }
2283
2284
2285 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002286 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002287 V8::FatalProcessOutOfMemory("String.replace result too large.");
2288 }
2289 character_count_ += by;
2290 }
2291
lrn@chromium.org25156de2010-04-06 13:10:27 +00002292 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002293 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002294 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002295
lrn@chromium.org25156de2010-04-06 13:10:27 +00002296 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002297 Handle<String> NewRawAsciiString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002298 CALL_HEAP_FUNCTION(heap_->isolate(),
2299 heap_->AllocateRawAsciiString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002300 }
2301
2302
2303 Handle<String> NewRawTwoByteString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002304 CALL_HEAP_FUNCTION(heap_->isolate(),
2305 heap_->AllocateRawTwoByteString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002306 }
2307
2308
2309 void AddElement(Object* element) {
2310 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002311 ASSERT(array_builder_.capacity() > array_builder_.length());
2312 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002313 }
2314
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002315 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002316 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002317 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002318 int character_count_;
2319 bool is_ascii_;
2320};
2321
2322
2323class CompiledReplacement {
2324 public:
2325 CompiledReplacement()
2326 : parts_(1), replacement_substrings_(0) {}
2327
2328 void Compile(Handle<String> replacement,
2329 int capture_count,
2330 int subject_length);
2331
2332 void Apply(ReplacementStringBuilder* builder,
2333 int match_from,
2334 int match_to,
2335 Handle<JSArray> last_match_info);
2336
2337 // Number of distinct parts of the replacement pattern.
2338 int parts() {
2339 return parts_.length();
2340 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002341
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002342 private:
2343 enum PartType {
2344 SUBJECT_PREFIX = 1,
2345 SUBJECT_SUFFIX,
2346 SUBJECT_CAPTURE,
2347 REPLACEMENT_SUBSTRING,
2348 REPLACEMENT_STRING,
2349
2350 NUMBER_OF_PART_TYPES
2351 };
2352
2353 struct ReplacementPart {
2354 static inline ReplacementPart SubjectMatch() {
2355 return ReplacementPart(SUBJECT_CAPTURE, 0);
2356 }
2357 static inline ReplacementPart SubjectCapture(int capture_index) {
2358 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2359 }
2360 static inline ReplacementPart SubjectPrefix() {
2361 return ReplacementPart(SUBJECT_PREFIX, 0);
2362 }
2363 static inline ReplacementPart SubjectSuffix(int subject_length) {
2364 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2365 }
2366 static inline ReplacementPart ReplacementString() {
2367 return ReplacementPart(REPLACEMENT_STRING, 0);
2368 }
2369 static inline ReplacementPart ReplacementSubString(int from, int to) {
2370 ASSERT(from >= 0);
2371 ASSERT(to > from);
2372 return ReplacementPart(-from, to);
2373 }
2374
2375 // If tag <= 0 then it is the negation of a start index of a substring of
2376 // the replacement pattern, otherwise it's a value from PartType.
2377 ReplacementPart(int tag, int data)
2378 : tag(tag), data(data) {
2379 // Must be non-positive or a PartType value.
2380 ASSERT(tag < NUMBER_OF_PART_TYPES);
2381 }
2382 // Either a value of PartType or a non-positive number that is
2383 // the negation of an index into the replacement string.
2384 int tag;
2385 // The data value's interpretation depends on the value of tag:
2386 // tag == SUBJECT_PREFIX ||
2387 // tag == SUBJECT_SUFFIX: data is unused.
2388 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2389 // tag == REPLACEMENT_SUBSTRING ||
2390 // tag == REPLACEMENT_STRING: data is index into array of substrings
2391 // of the replacement string.
2392 // tag <= 0: Temporary representation of the substring of the replacement
2393 // string ranging over -tag .. data.
2394 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2395 // substring objects.
2396 int data;
2397 };
2398
2399 template<typename Char>
2400 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2401 Vector<Char> characters,
2402 int capture_count,
2403 int subject_length) {
2404 int length = characters.length();
2405 int last = 0;
2406 for (int i = 0; i < length; i++) {
2407 Char c = characters[i];
2408 if (c == '$') {
2409 int next_index = i + 1;
2410 if (next_index == length) { // No next character!
2411 break;
2412 }
2413 Char c2 = characters[next_index];
2414 switch (c2) {
2415 case '$':
2416 if (i > last) {
2417 // There is a substring before. Include the first "$".
2418 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2419 last = next_index + 1; // Continue after the second "$".
2420 } else {
2421 // Let the next substring start with the second "$".
2422 last = next_index;
2423 }
2424 i = next_index;
2425 break;
2426 case '`':
2427 if (i > last) {
2428 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2429 }
2430 parts->Add(ReplacementPart::SubjectPrefix());
2431 i = next_index;
2432 last = i + 1;
2433 break;
2434 case '\'':
2435 if (i > last) {
2436 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2437 }
2438 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2439 i = next_index;
2440 last = i + 1;
2441 break;
2442 case '&':
2443 if (i > last) {
2444 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2445 }
2446 parts->Add(ReplacementPart::SubjectMatch());
2447 i = next_index;
2448 last = i + 1;
2449 break;
2450 case '0':
2451 case '1':
2452 case '2':
2453 case '3':
2454 case '4':
2455 case '5':
2456 case '6':
2457 case '7':
2458 case '8':
2459 case '9': {
2460 int capture_ref = c2 - '0';
2461 if (capture_ref > capture_count) {
2462 i = next_index;
2463 continue;
2464 }
2465 int second_digit_index = next_index + 1;
2466 if (second_digit_index < length) {
2467 // Peek ahead to see if we have two digits.
2468 Char c3 = characters[second_digit_index];
2469 if ('0' <= c3 && c3 <= '9') { // Double digits.
2470 int double_digit_ref = capture_ref * 10 + c3 - '0';
2471 if (double_digit_ref <= capture_count) {
2472 next_index = second_digit_index;
2473 capture_ref = double_digit_ref;
2474 }
2475 }
2476 }
2477 if (capture_ref > 0) {
2478 if (i > last) {
2479 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2480 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002481 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002482 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2483 last = next_index + 1;
2484 }
2485 i = next_index;
2486 break;
2487 }
2488 default:
2489 i = next_index;
2490 break;
2491 }
2492 }
2493 }
2494 if (length > last) {
2495 if (last == 0) {
2496 parts->Add(ReplacementPart::ReplacementString());
2497 } else {
2498 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2499 }
2500 }
2501 }
2502
2503 ZoneList<ReplacementPart> parts_;
2504 ZoneList<Handle<String> > replacement_substrings_;
2505};
2506
2507
2508void CompiledReplacement::Compile(Handle<String> replacement,
2509 int capture_count,
2510 int subject_length) {
2511 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002512 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002513 AssertNoAllocation no_alloc;
2514 ParseReplacementPattern(&parts_,
2515 replacement->ToAsciiVector(),
2516 capture_count,
2517 subject_length);
2518 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002519 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002520 AssertNoAllocation no_alloc;
2521
2522 ParseReplacementPattern(&parts_,
2523 replacement->ToUC16Vector(),
2524 capture_count,
2525 subject_length);
2526 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002527 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002528 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002529 int substring_index = 0;
2530 for (int i = 0, n = parts_.length(); i < n; i++) {
2531 int tag = parts_[i].tag;
2532 if (tag <= 0) { // A replacement string slice.
2533 int from = -tag;
2534 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002535 replacement_substrings_.Add(
2536 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002537 parts_[i].tag = REPLACEMENT_SUBSTRING;
2538 parts_[i].data = substring_index;
2539 substring_index++;
2540 } else if (tag == REPLACEMENT_STRING) {
2541 replacement_substrings_.Add(replacement);
2542 parts_[i].data = substring_index;
2543 substring_index++;
2544 }
2545 }
2546}
2547
2548
2549void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2550 int match_from,
2551 int match_to,
2552 Handle<JSArray> last_match_info) {
2553 for (int i = 0, n = parts_.length(); i < n; i++) {
2554 ReplacementPart part = parts_[i];
2555 switch (part.tag) {
2556 case SUBJECT_PREFIX:
2557 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2558 break;
2559 case SUBJECT_SUFFIX: {
2560 int subject_length = part.data;
2561 if (match_to < subject_length) {
2562 builder->AddSubjectSlice(match_to, subject_length);
2563 }
2564 break;
2565 }
2566 case SUBJECT_CAPTURE: {
2567 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002568 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002569 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2570 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2571 if (from >= 0 && to > from) {
2572 builder->AddSubjectSlice(from, to);
2573 }
2574 break;
2575 }
2576 case REPLACEMENT_SUBSTRING:
2577 case REPLACEMENT_STRING:
2578 builder->AddString(replacement_substrings_[part.data]);
2579 break;
2580 default:
2581 UNREACHABLE();
2582 }
2583 }
2584}
2585
2586
2587
lrn@chromium.org303ada72010-10-27 09:33:13 +00002588MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002589 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002590 String* subject,
2591 JSRegExp* regexp,
2592 String* replacement,
2593 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002594 ASSERT(subject->IsFlat());
2595 ASSERT(replacement->IsFlat());
2596
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002597 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002598
2599 int length = subject->length();
2600 Handle<String> subject_handle(subject);
2601 Handle<JSRegExp> regexp_handle(regexp);
2602 Handle<String> replacement_handle(replacement);
2603 Handle<JSArray> last_match_info_handle(last_match_info);
2604 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2605 subject_handle,
2606 0,
2607 last_match_info_handle);
2608 if (match.is_null()) {
2609 return Failure::Exception();
2610 }
2611 if (match->IsNull()) {
2612 return *subject_handle;
2613 }
2614
2615 int capture_count = regexp_handle->CaptureCount();
2616
2617 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002618 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002619 CompiledReplacement compiled_replacement;
2620 compiled_replacement.Compile(replacement_handle,
2621 capture_count,
2622 length);
2623
2624 bool is_global = regexp_handle->GetFlags().is_global();
2625
2626 // Guessing the number of parts that the final result string is built
2627 // from. Global regexps can match any number of times, so we guess
2628 // conservatively.
2629 int expected_parts =
2630 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002631 ReplacementStringBuilder builder(isolate->heap(),
2632 subject_handle,
2633 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002634
2635 // Index of end of last match.
2636 int prev = 0;
2637
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002638 // Number of parts added by compiled replacement plus preceeding
2639 // string and possibly suffix after last match. It is possible for
2640 // all components to use two elements when encoded as two smis.
2641 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002642 bool matched = true;
2643 do {
2644 ASSERT(last_match_info_handle->HasFastElements());
2645 // Increase the capacity of the builder before entering local handle-scope,
2646 // so its internal buffer can safely allocate a new handle if it grows.
2647 builder.EnsureCapacity(parts_added_per_loop);
2648
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002649 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002650 int start, end;
2651 {
2652 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002653 FixedArray* match_info_array =
2654 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002655
2656 ASSERT_EQ(capture_count * 2 + 2,
2657 RegExpImpl::GetLastCaptureCount(match_info_array));
2658 start = RegExpImpl::GetCapture(match_info_array, 0);
2659 end = RegExpImpl::GetCapture(match_info_array, 1);
2660 }
2661
2662 if (prev < start) {
2663 builder.AddSubjectSlice(prev, start);
2664 }
2665 compiled_replacement.Apply(&builder,
2666 start,
2667 end,
2668 last_match_info_handle);
2669 prev = end;
2670
2671 // Only continue checking for global regexps.
2672 if (!is_global) break;
2673
2674 // Continue from where the match ended, unless it was an empty match.
2675 int next = end;
2676 if (start == end) {
2677 next = end + 1;
2678 if (next > length) break;
2679 }
2680
2681 match = RegExpImpl::Exec(regexp_handle,
2682 subject_handle,
2683 next,
2684 last_match_info_handle);
2685 if (match.is_null()) {
2686 return Failure::Exception();
2687 }
2688 matched = !match->IsNull();
2689 } while (matched);
2690
2691 if (prev < length) {
2692 builder.AddSubjectSlice(prev, length);
2693 }
2694
2695 return *(builder.ToString());
2696}
2697
2698
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002699template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002700MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002701 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002702 String* subject,
2703 JSRegExp* regexp,
2704 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002705 ASSERT(subject->IsFlat());
2706
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002707 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002708
2709 Handle<String> subject_handle(subject);
2710 Handle<JSRegExp> regexp_handle(regexp);
2711 Handle<JSArray> last_match_info_handle(last_match_info);
2712 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2713 subject_handle,
2714 0,
2715 last_match_info_handle);
2716 if (match.is_null()) return Failure::Exception();
2717 if (match->IsNull()) return *subject_handle;
2718
2719 ASSERT(last_match_info_handle->HasFastElements());
2720
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002721 int start, end;
2722 {
2723 AssertNoAllocation match_info_array_is_not_in_a_handle;
2724 FixedArray* match_info_array =
2725 FixedArray::cast(last_match_info_handle->elements());
2726
2727 start = RegExpImpl::GetCapture(match_info_array, 0);
2728 end = RegExpImpl::GetCapture(match_info_array, 1);
2729 }
2730
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002731 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002732 int new_length = length - (end - start);
2733 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002734 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002735 }
2736 Handle<ResultSeqString> answer;
2737 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002738 answer = Handle<ResultSeqString>::cast(
2739 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002740 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002741 answer = Handle<ResultSeqString>::cast(
2742 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002743 }
2744
2745 // If the regexp isn't global, only match once.
2746 if (!regexp_handle->GetFlags().is_global()) {
2747 if (start > 0) {
2748 String::WriteToFlat(*subject_handle,
2749 answer->GetChars(),
2750 0,
2751 start);
2752 }
2753 if (end < length) {
2754 String::WriteToFlat(*subject_handle,
2755 answer->GetChars() + start,
2756 end,
2757 length);
2758 }
2759 return *answer;
2760 }
2761
2762 int prev = 0; // Index of end of last match.
2763 int next = 0; // Start of next search (prev unless last match was empty).
2764 int position = 0;
2765
2766 do {
2767 if (prev < start) {
2768 // Add substring subject[prev;start] to answer string.
2769 String::WriteToFlat(*subject_handle,
2770 answer->GetChars() + position,
2771 prev,
2772 start);
2773 position += start - prev;
2774 }
2775 prev = end;
2776 next = end;
2777 // Continue from where the match ended, unless it was an empty match.
2778 if (start == end) {
2779 next++;
2780 if (next > length) break;
2781 }
2782 match = RegExpImpl::Exec(regexp_handle,
2783 subject_handle,
2784 next,
2785 last_match_info_handle);
2786 if (match.is_null()) return Failure::Exception();
2787 if (match->IsNull()) break;
2788
2789 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002790 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002791 {
2792 AssertNoAllocation match_info_array_is_not_in_a_handle;
2793 FixedArray* match_info_array =
2794 FixedArray::cast(last_match_info_handle->elements());
2795 start = RegExpImpl::GetCapture(match_info_array, 0);
2796 end = RegExpImpl::GetCapture(match_info_array, 1);
2797 }
2798 } while (true);
2799
2800 if (prev < length) {
2801 // Add substring subject[prev;length] to answer string.
2802 String::WriteToFlat(*subject_handle,
2803 answer->GetChars() + position,
2804 prev,
2805 length);
2806 position += length - prev;
2807 }
2808
2809 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002810 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002811 }
2812
2813 // Shorten string and fill
2814 int string_size = ResultSeqString::SizeFor(position);
2815 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2816 int delta = allocated_string_size - string_size;
2817
2818 answer->set_length(position);
2819 if (delta == 0) return *answer;
2820
2821 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002822 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002823
2824 return *answer;
2825}
2826
2827
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002828RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002829 ASSERT(args.length() == 4);
2830
2831 CONVERT_CHECKED(String, subject, args[0]);
2832 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002833 Object* flat_subject;
2834 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2835 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2836 return maybe_flat_subject;
2837 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002838 }
2839 subject = String::cast(flat_subject);
2840 }
2841
2842 CONVERT_CHECKED(String, replacement, args[2]);
2843 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002844 Object* flat_replacement;
2845 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2846 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2847 return maybe_flat_replacement;
2848 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002849 }
2850 replacement = String::cast(flat_replacement);
2851 }
2852
2853 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2854 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2855
2856 ASSERT(last_match_info->HasFastElements());
2857
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002858 if (replacement->length() == 0) {
2859 if (subject->HasOnlyAsciiChars()) {
2860 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002861 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002862 } else {
2863 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002864 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002865 }
2866 }
2867
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002868 return StringReplaceRegExpWithString(isolate,
2869 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002870 regexp,
2871 replacement,
2872 last_match_info);
2873}
2874
2875
ager@chromium.org7c537e22008-10-16 08:43:32 +00002876// Perform string match of pattern on subject, starting at start index.
2877// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002878// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002879int Runtime::StringMatch(Isolate* isolate,
2880 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002881 Handle<String> pat,
2882 int start_index) {
2883 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002884 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002885
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002886 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002887 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002888
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002889 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002890 if (start_index + pattern_length > subject_length) return -1;
2891
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002892 if (!sub->IsFlat()) FlattenString(sub);
2893 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002894
ager@chromium.org7c537e22008-10-16 08:43:32 +00002895 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002896 // Extract flattened substrings of cons strings before determining asciiness.
2897 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002898 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002899 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002900 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002901
ager@chromium.org7c537e22008-10-16 08:43:32 +00002902 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002903 if (seq_pat->IsAsciiRepresentation()) {
2904 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2905 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002906 return SearchString(isolate,
2907 seq_sub->ToAsciiVector(),
2908 pat_vector,
2909 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002910 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002911 return SearchString(isolate,
2912 seq_sub->ToUC16Vector(),
2913 pat_vector,
2914 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002915 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002916 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2917 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002918 return SearchString(isolate,
2919 seq_sub->ToAsciiVector(),
2920 pat_vector,
2921 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002922 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002923 return SearchString(isolate,
2924 seq_sub->ToUC16Vector(),
2925 pat_vector,
2926 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002927}
2928
2929
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002930RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002931 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002932 ASSERT(args.length() == 3);
2933
ager@chromium.org7c537e22008-10-16 08:43:32 +00002934 CONVERT_ARG_CHECKED(String, sub, 0);
2935 CONVERT_ARG_CHECKED(String, pat, 1);
2936
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002937 Object* index = args[2];
2938 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002939 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002940
ager@chromium.org870a0b62008-11-04 11:43:05 +00002941 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002942 int position =
2943 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002944 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002945}
2946
2947
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002948template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002949static int StringMatchBackwards(Vector<const schar> subject,
2950 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002951 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002952 int pattern_length = pattern.length();
2953 ASSERT(pattern_length >= 1);
2954 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002955
2956 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002957 for (int i = 0; i < pattern_length; i++) {
2958 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002959 if (c > String::kMaxAsciiCharCode) {
2960 return -1;
2961 }
2962 }
2963 }
2964
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002965 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002966 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002967 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002968 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002969 while (j < pattern_length) {
2970 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002971 break;
2972 }
2973 j++;
2974 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002975 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002976 return i;
2977 }
2978 }
2979 return -1;
2980}
2981
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002982RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002983 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002984 ASSERT(args.length() == 3);
2985
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002986 CONVERT_ARG_CHECKED(String, sub, 0);
2987 CONVERT_ARG_CHECKED(String, pat, 1);
2988
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002989 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002990 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002991 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002992
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002993 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002994 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002995
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002996 if (start_index + pat_length > sub_length) {
2997 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002998 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002999
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003000 if (pat_length == 0) {
3001 return Smi::FromInt(start_index);
3002 }
3003
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003004 if (!sub->IsFlat()) FlattenString(sub);
3005 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003006
3007 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3008
3009 int position = -1;
3010
3011 if (pat->IsAsciiRepresentation()) {
3012 Vector<const char> pat_vector = pat->ToAsciiVector();
3013 if (sub->IsAsciiRepresentation()) {
3014 position = StringMatchBackwards(sub->ToAsciiVector(),
3015 pat_vector,
3016 start_index);
3017 } else {
3018 position = StringMatchBackwards(sub->ToUC16Vector(),
3019 pat_vector,
3020 start_index);
3021 }
3022 } else {
3023 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3024 if (sub->IsAsciiRepresentation()) {
3025 position = StringMatchBackwards(sub->ToAsciiVector(),
3026 pat_vector,
3027 start_index);
3028 } else {
3029 position = StringMatchBackwards(sub->ToUC16Vector(),
3030 pat_vector,
3031 start_index);
3032 }
3033 }
3034
3035 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003036}
3037
3038
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003039RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003040 NoHandleAllocation ha;
3041 ASSERT(args.length() == 2);
3042
3043 CONVERT_CHECKED(String, str1, args[0]);
3044 CONVERT_CHECKED(String, str2, args[1]);
3045
3046 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003047 int str1_length = str1->length();
3048 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003049
3050 // Decide trivial cases without flattening.
3051 if (str1_length == 0) {
3052 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3053 return Smi::FromInt(-str2_length);
3054 } else {
3055 if (str2_length == 0) return Smi::FromInt(str1_length);
3056 }
3057
3058 int end = str1_length < str2_length ? str1_length : str2_length;
3059
3060 // No need to flatten if we are going to find the answer on the first
3061 // character. At this point we know there is at least one character
3062 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003063 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003064 if (d != 0) return Smi::FromInt(d);
3065
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003066 str1->TryFlatten();
3067 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003068
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003069 StringInputBuffer& buf1 =
3070 *isolate->runtime_state()->string_locale_compare_buf1();
3071 StringInputBuffer& buf2 =
3072 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003073
3074 buf1.Reset(str1);
3075 buf2.Reset(str2);
3076
3077 for (int i = 0; i < end; i++) {
3078 uint16_t char1 = buf1.GetNext();
3079 uint16_t char2 = buf2.GetNext();
3080 if (char1 != char2) return Smi::FromInt(char1 - char2);
3081 }
3082
3083 return Smi::FromInt(str1_length - str2_length);
3084}
3085
3086
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003087RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003088 NoHandleAllocation ha;
3089 ASSERT(args.length() == 3);
3090
3091 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003092 int start, end;
3093 // We have a fast integer-only case here to avoid a conversion to double in
3094 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003095 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3096 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3097 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3098 start = from_number;
3099 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003100 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003101 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3102 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003103 start = FastD2I(from_number);
3104 end = FastD2I(to_number);
3105 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003106 RUNTIME_ASSERT(end >= start);
3107 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003108 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003109 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003110 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003111}
3112
3113
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003114RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003115 ASSERT_EQ(3, args.length());
3116
3117 CONVERT_ARG_CHECKED(String, subject, 0);
3118 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3119 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3120 HandleScope handles;
3121
3122 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3123
3124 if (match.is_null()) {
3125 return Failure::Exception();
3126 }
3127 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003128 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003129 }
3130 int length = subject->length();
3131
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003132 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003133 ZoneList<int> offsets(8);
3134 do {
3135 int start;
3136 int end;
3137 {
3138 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003139 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003140 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3141 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3142 }
3143 offsets.Add(start);
3144 offsets.Add(end);
3145 int index = start < end ? end : end + 1;
3146 if (index > length) break;
3147 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3148 if (match.is_null()) {
3149 return Failure::Exception();
3150 }
3151 } while (!match->IsNull());
3152 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003153 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org41826e72009-03-30 13:30:57 +00003154 for (int i = 0; i < matches ; i++) {
3155 int from = offsets.at(i * 2);
3156 int to = offsets.at(i * 2 + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003157 Handle<String> match = isolate->factory()->NewSubString(subject, from, to);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003158 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00003159 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003160 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003161 result->set_length(Smi::FromInt(matches));
3162 return *result;
3163}
3164
3165
lrn@chromium.org25156de2010-04-06 13:10:27 +00003166// Two smis before and after the match, for very long strings.
3167const int kMaxBuilderEntriesPerRegExpMatch = 5;
3168
3169
3170static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3171 Handle<JSArray> last_match_info,
3172 int match_start,
3173 int match_end) {
3174 // Fill last_match_info with a single capture.
3175 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3176 AssertNoAllocation no_gc;
3177 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3178 RegExpImpl::SetLastCaptureCount(elements, 2);
3179 RegExpImpl::SetLastInput(elements, *subject);
3180 RegExpImpl::SetLastSubject(elements, *subject);
3181 RegExpImpl::SetCapture(elements, 0, match_start);
3182 RegExpImpl::SetCapture(elements, 1, match_end);
3183}
3184
3185
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003186template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003187static bool SearchStringMultiple(Isolate* isolate,
3188 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003189 Vector<const PatternChar> pattern,
3190 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003191 FixedArrayBuilder* builder,
3192 int* match_pos) {
3193 int pos = *match_pos;
3194 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003195 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003196 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003197 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003198 while (pos <= max_search_start) {
3199 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3200 *match_pos = pos;
3201 return false;
3202 }
3203 // Position of end of previous match.
3204 int match_end = pos + pattern_length;
3205 int new_pos = search.Search(subject, match_end);
3206 if (new_pos >= 0) {
3207 // A match.
3208 if (new_pos > match_end) {
3209 ReplacementStringBuilder::AddSubjectSlice(builder,
3210 match_end,
3211 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003212 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003213 pos = new_pos;
3214 builder->Add(pattern_string);
3215 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003216 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003217 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003218 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003219
lrn@chromium.org25156de2010-04-06 13:10:27 +00003220 if (pos < max_search_start) {
3221 ReplacementStringBuilder::AddSubjectSlice(builder,
3222 pos + pattern_length,
3223 subject_length);
3224 }
3225 *match_pos = pos;
3226 return true;
3227}
3228
3229
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003230static bool SearchStringMultiple(Isolate* isolate,
3231 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003232 Handle<String> pattern,
3233 Handle<JSArray> last_match_info,
3234 FixedArrayBuilder* builder) {
3235 ASSERT(subject->IsFlat());
3236 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003237
3238 // Treating as if a previous match was before first character.
3239 int match_pos = -pattern->length();
3240
3241 for (;;) { // Break when search complete.
3242 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3243 AssertNoAllocation no_gc;
3244 if (subject->IsAsciiRepresentation()) {
3245 Vector<const char> subject_vector = subject->ToAsciiVector();
3246 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003247 if (SearchStringMultiple(isolate,
3248 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003249 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003250 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003251 builder,
3252 &match_pos)) break;
3253 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003254 if (SearchStringMultiple(isolate,
3255 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003256 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003257 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003258 builder,
3259 &match_pos)) break;
3260 }
3261 } else {
3262 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3263 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003264 if (SearchStringMultiple(isolate,
3265 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003266 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003267 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003268 builder,
3269 &match_pos)) break;
3270 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003271 if (SearchStringMultiple(isolate,
3272 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003273 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003274 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003275 builder,
3276 &match_pos)) break;
3277 }
3278 }
3279 }
3280
3281 if (match_pos >= 0) {
3282 SetLastMatchInfoNoCaptures(subject,
3283 last_match_info,
3284 match_pos,
3285 match_pos + pattern->length());
3286 return true;
3287 }
3288 return false; // No matches at all.
3289}
3290
3291
3292static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003293 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003294 Handle<String> subject,
3295 Handle<JSRegExp> regexp,
3296 Handle<JSArray> last_match_array,
3297 FixedArrayBuilder* builder) {
3298 ASSERT(subject->IsFlat());
3299 int match_start = -1;
3300 int match_end = 0;
3301 int pos = 0;
3302 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3303 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3304
3305 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003306 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003307 int subject_length = subject->length();
3308
3309 for (;;) { // Break on failure, return on exception.
3310 RegExpImpl::IrregexpResult result =
3311 RegExpImpl::IrregexpExecOnce(regexp,
3312 subject,
3313 pos,
3314 register_vector);
3315 if (result == RegExpImpl::RE_SUCCESS) {
3316 match_start = register_vector[0];
3317 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3318 if (match_end < match_start) {
3319 ReplacementStringBuilder::AddSubjectSlice(builder,
3320 match_end,
3321 match_start);
3322 }
3323 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003324 HandleScope loop_scope(isolate);
3325 builder->Add(*isolate->factory()->NewSubString(subject,
3326 match_start,
3327 match_end));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003328 if (match_start != match_end) {
3329 pos = match_end;
3330 } else {
3331 pos = match_end + 1;
3332 if (pos > subject_length) break;
3333 }
3334 } else if (result == RegExpImpl::RE_FAILURE) {
3335 break;
3336 } else {
3337 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3338 return result;
3339 }
3340 }
3341
3342 if (match_start >= 0) {
3343 if (match_end < subject_length) {
3344 ReplacementStringBuilder::AddSubjectSlice(builder,
3345 match_end,
3346 subject_length);
3347 }
3348 SetLastMatchInfoNoCaptures(subject,
3349 last_match_array,
3350 match_start,
3351 match_end);
3352 return RegExpImpl::RE_SUCCESS;
3353 } else {
3354 return RegExpImpl::RE_FAILURE; // No matches at all.
3355 }
3356}
3357
3358
3359static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003360 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003361 Handle<String> subject,
3362 Handle<JSRegExp> regexp,
3363 Handle<JSArray> last_match_array,
3364 FixedArrayBuilder* builder) {
3365
3366 ASSERT(subject->IsFlat());
3367 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3368 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3369
3370 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003371 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003372
3373 RegExpImpl::IrregexpResult result =
3374 RegExpImpl::IrregexpExecOnce(regexp,
3375 subject,
3376 0,
3377 register_vector);
3378
3379 int capture_count = regexp->CaptureCount();
3380 int subject_length = subject->length();
3381
3382 // Position to search from.
3383 int pos = 0;
3384 // End of previous match. Differs from pos if match was empty.
3385 int match_end = 0;
3386 if (result == RegExpImpl::RE_SUCCESS) {
3387 // Need to keep a copy of the previous match for creating last_match_info
3388 // at the end, so we have two vectors that we swap between.
3389 OffsetsVector registers2(required_registers);
3390 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3391
3392 do {
3393 int match_start = register_vector[0];
3394 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3395 if (match_end < match_start) {
3396 ReplacementStringBuilder::AddSubjectSlice(builder,
3397 match_end,
3398 match_start);
3399 }
3400 match_end = register_vector[1];
3401
3402 {
3403 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003404 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003405 // Arguments array to replace function is match, captures, index and
3406 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003407 Handle<FixedArray> elements =
3408 isolate->factory()->NewFixedArray(3 + capture_count);
3409 Handle<String> match = isolate->factory()->NewSubString(subject,
3410 match_start,
3411 match_end);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003412 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003413 for (int i = 1; i <= capture_count; i++) {
3414 int start = register_vector[i * 2];
3415 if (start >= 0) {
3416 int end = register_vector[i * 2 + 1];
3417 ASSERT(start <= end);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003418 Handle<String> substring = isolate->factory()->NewSubString(subject,
3419 start,
3420 end);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003421 elements->set(i, *substring);
3422 } else {
3423 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003424 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003425 }
3426 }
3427 elements->set(capture_count + 1, Smi::FromInt(match_start));
3428 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003429 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003430 }
3431 // Swap register vectors, so the last successful match is in
3432 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003433 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003434 prev_register_vector = register_vector;
3435 register_vector = tmp;
3436
3437 if (match_end > match_start) {
3438 pos = match_end;
3439 } else {
3440 pos = match_end + 1;
3441 if (pos > subject_length) {
3442 break;
3443 }
3444 }
3445
3446 result = RegExpImpl::IrregexpExecOnce(regexp,
3447 subject,
3448 pos,
3449 register_vector);
3450 } while (result == RegExpImpl::RE_SUCCESS);
3451
3452 if (result != RegExpImpl::RE_EXCEPTION) {
3453 // Finished matching, with at least one match.
3454 if (match_end < subject_length) {
3455 ReplacementStringBuilder::AddSubjectSlice(builder,
3456 match_end,
3457 subject_length);
3458 }
3459
3460 int last_match_capture_count = (capture_count + 1) * 2;
3461 int last_match_array_size =
3462 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3463 last_match_array->EnsureSize(last_match_array_size);
3464 AssertNoAllocation no_gc;
3465 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3466 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3467 RegExpImpl::SetLastSubject(elements, *subject);
3468 RegExpImpl::SetLastInput(elements, *subject);
3469 for (int i = 0; i < last_match_capture_count; i++) {
3470 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3471 }
3472 return RegExpImpl::RE_SUCCESS;
3473 }
3474 }
3475 // No matches at all, return failure or exception result directly.
3476 return result;
3477}
3478
3479
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003480RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003481 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003482 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003483
3484 CONVERT_ARG_CHECKED(String, subject, 1);
3485 if (!subject->IsFlat()) { FlattenString(subject); }
3486 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3487 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3488 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3489
3490 ASSERT(last_match_info->HasFastElements());
3491 ASSERT(regexp->GetFlags().is_global());
3492 Handle<FixedArray> result_elements;
3493 if (result_array->HasFastElements()) {
3494 result_elements =
3495 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3496 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003497 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003498 }
3499 FixedArrayBuilder builder(result_elements);
3500
3501 if (regexp->TypeTag() == JSRegExp::ATOM) {
3502 Handle<String> pattern(
3503 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003504 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003505 if (SearchStringMultiple(isolate, subject, pattern,
3506 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003507 return *builder.ToJSArray(result_array);
3508 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003509 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003510 }
3511
3512 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3513
3514 RegExpImpl::IrregexpResult result;
3515 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003516 result = SearchRegExpNoCaptureMultiple(isolate,
3517 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003518 regexp,
3519 last_match_info,
3520 &builder);
3521 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003522 result = SearchRegExpMultiple(isolate,
3523 subject,
3524 regexp,
3525 last_match_info,
3526 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003527 }
3528 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003529 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003530 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3531 return Failure::Exception();
3532}
3533
3534
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003535RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003536 NoHandleAllocation ha;
3537 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003538 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003539 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003540
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003541 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003542 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003543 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003544 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003545 // Character array used for conversion.
3546 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003547 return isolate->heap()->
3548 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003549 }
3550 }
3551
3552 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003553 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003554 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003555 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003556 }
3557 if (isinf(value)) {
3558 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003559 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003560 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003561 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003562 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003563 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003564 MaybeObject* result =
3565 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003566 DeleteArray(str);
3567 return result;
3568}
3569
3570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003571RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003572 NoHandleAllocation ha;
3573 ASSERT(args.length() == 2);
3574
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003575 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003576 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003577 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003578 }
3579 if (isinf(value)) {
3580 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003581 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003582 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003583 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003584 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003585 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003586 int f = FastD2I(f_number);
3587 RUNTIME_ASSERT(f >= 0);
3588 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003589 MaybeObject* res =
3590 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003591 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003592 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003593}
3594
3595
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003596RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003597 NoHandleAllocation ha;
3598 ASSERT(args.length() == 2);
3599
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003600 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003601 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003602 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003603 }
3604 if (isinf(value)) {
3605 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003606 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003607 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003608 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003609 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003610 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003611 int f = FastD2I(f_number);
3612 RUNTIME_ASSERT(f >= -1 && f <= 20);
3613 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003614 MaybeObject* res =
3615 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003616 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003617 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003618}
3619
3620
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003621RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003622 NoHandleAllocation ha;
3623 ASSERT(args.length() == 2);
3624
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003625 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003626 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003627 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003628 }
3629 if (isinf(value)) {
3630 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003631 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003632 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003633 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003634 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003635 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003636 int f = FastD2I(f_number);
3637 RUNTIME_ASSERT(f >= 1 && f <= 21);
3638 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003639 MaybeObject* res =
3640 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003641 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003642 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003643}
3644
3645
3646// Returns a single character string where first character equals
3647// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003648static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003649 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003650 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003651 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003652 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003653 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003654 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003655}
3656
3657
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003658MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3659 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003660 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003661 // Handle [] indexing on Strings
3662 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003663 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3664 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003665 }
3666
3667 // Handle [] indexing on String objects
3668 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003669 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3670 Handle<Object> result =
3671 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3672 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003673 }
3674
3675 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003676 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003677 return prototype->GetElement(index);
3678 }
3679
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003680 return GetElement(object, index);
3681}
3682
3683
lrn@chromium.org303ada72010-10-27 09:33:13 +00003684MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003685 return object->GetElement(index);
3686}
3687
3688
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003689MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3690 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003691 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003692 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003693
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003694 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003695 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003696 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003697 isolate->factory()->NewTypeError("non_object_property_load",
3698 HandleVector(args, 2));
3699 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003700 }
3701
3702 // Check if the given key is an array index.
3703 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003704 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003705 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003706 }
3707
3708 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003709 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003710 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003711 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003712 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003713 bool has_pending_exception = false;
3714 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003715 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003716 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003717 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003718 }
3719
ager@chromium.org32912102009-01-16 10:38:43 +00003720 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003721 // the element if so.
3722 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003723 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003724 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003725 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003726 }
3727}
3728
3729
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003730RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003731 NoHandleAllocation ha;
3732 ASSERT(args.length() == 2);
3733
3734 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003735 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003736
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003737 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003738}
3739
3740
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003741// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003742RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003743 NoHandleAllocation ha;
3744 ASSERT(args.length() == 2);
3745
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003746 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003747 // itself.
3748 //
3749 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003750 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003751 // global proxy object never has properties. This is the case
3752 // because the global proxy object forwards everything to its hidden
3753 // prototype including local lookups.
3754 //
3755 // Additionally, we need to make sure that we do not cache results
3756 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003757 if (args[0]->IsJSObject() &&
3758 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003759 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003760 args[1]->IsString()) {
3761 JSObject* receiver = JSObject::cast(args[0]);
3762 String* key = String::cast(args[1]);
3763 if (receiver->HasFastProperties()) {
3764 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003765 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003766 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3767 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003768 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003769 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003770 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003771 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003772 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003773 LookupResult result;
3774 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003775 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003776 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003777 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003778 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003779 }
3780 } else {
3781 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003782 StringDictionary* dictionary = receiver->property_dictionary();
3783 int entry = dictionary->FindEntry(key);
3784 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003785 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003786 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003787 if (!receiver->IsGlobalObject()) return value;
3788 value = JSGlobalPropertyCell::cast(value)->value();
3789 if (!value->IsTheHole()) return value;
3790 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003791 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003792 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003793 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3794 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003795 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003796 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003797 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003798 if (index >= 0 && index < str->length()) {
3799 Handle<Object> result = GetCharAt(str, index);
3800 return *result;
3801 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003802 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003803
3804 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003805 return Runtime::GetObjectProperty(isolate,
3806 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003807 args.at<Object>(1));
3808}
3809
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003810// Implements part of 8.12.9 DefineOwnProperty.
3811// There are 3 cases that lead here:
3812// Step 4b - define a new accessor property.
3813// Steps 9c & 12 - replace an existing data property with an accessor property.
3814// Step 12 - update an existing accessor property with an accessor or generic
3815// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003816RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003817 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003818 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003819 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3820 CONVERT_CHECKED(String, name, args[1]);
3821 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003822 Object* fun = args[3];
3823 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003824 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3825 int unchecked = flag_attr->value();
3826 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3827 RUNTIME_ASSERT(!obj->IsNull());
3828 LookupResult result;
3829 obj->LocalLookupRealNamedProperty(name, &result);
3830
3831 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3832 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3833 // delete it to avoid running into trouble in DefineAccessor, which
3834 // handles this incorrectly if the property is readonly (does nothing)
3835 if (result.IsProperty() &&
3836 (result.type() == FIELD || result.type() == NORMAL
3837 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003838 Object* ok;
3839 { MaybeObject* maybe_ok =
3840 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3841 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3842 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003843 }
3844 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3845}
3846
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003847// Implements part of 8.12.9 DefineOwnProperty.
3848// There are 3 cases that lead here:
3849// Step 4a - define a new data property.
3850// Steps 9b & 12 - replace an existing accessor property with a data property.
3851// Step 12 - update an existing data property with a data or generic
3852// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003853RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003854 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003855 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003856 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3857 CONVERT_ARG_CHECKED(String, name, 1);
3858 Handle<Object> obj_value = args.at<Object>(2);
3859
3860 CONVERT_CHECKED(Smi, flag, args[3]);
3861 int unchecked = flag->value();
3862 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3863
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003864 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3865
3866 // Check if this is an element.
3867 uint32_t index;
3868 bool is_element = name->AsArrayIndex(&index);
3869
3870 // Special case for elements if any of the flags are true.
3871 // If elements are in fast case we always implicitly assume that:
3872 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3873 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3874 is_element) {
3875 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003876 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003877 // We do not need to do access checks here since these has already
3878 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003879 Handle<Object> proto(js_object->GetPrototype());
3880 // If proxy is detached, ignore the assignment. Alternatively,
3881 // we could throw an exception.
3882 if (proto->IsNull()) return *obj_value;
3883 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003884 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003885 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003886 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003887 // Make sure that we never go back to fast case.
3888 dictionary->set_requires_slow_elements();
3889 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003890 Handle<NumberDictionary> extended_dictionary =
3891 NumberDictionarySet(dictionary, index, obj_value, details);
3892 if (*extended_dictionary != *dictionary) {
3893 js_object->set_elements(*extended_dictionary);
3894 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003895 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003896 }
3897
ager@chromium.org5c838252010-02-19 08:53:10 +00003898 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003899 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003900
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003901 // To be compatible with safari we do not change the value on API objects
3902 // in defineProperty. Firefox disagrees here, and actually changes the value.
3903 if (result.IsProperty() &&
3904 (result.type() == CALLBACKS) &&
3905 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003906 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003907 }
3908
ager@chromium.org5c838252010-02-19 08:53:10 +00003909 // Take special care when attributes are different and there is already
3910 // a property. For simplicity we normalize the property which enables us
3911 // to not worry about changing the instance_descriptor and creating a new
3912 // map. The current version of SetObjectProperty does not handle attributes
3913 // correctly in the case where a property is a field and is reset with
3914 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003915 if (result.IsProperty() &&
3916 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003917 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003918 if (js_object->IsJSGlobalProxy()) {
3919 // Since the result is a property, the prototype will exist so
3920 // we don't have to check for null.
3921 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003922 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003923 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003924 // Use IgnoreAttributes version since a readonly property may be
3925 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003926 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3927 *obj_value,
3928 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003929 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003930
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003931 return Runtime::ForceSetObjectProperty(isolate,
3932 js_object,
3933 name,
3934 obj_value,
3935 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003936}
3937
3938
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003939// Special case for elements if any of the flags are true.
3940// If elements are in fast case we always implicitly assume that:
3941// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3942static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
3943 Handle<JSObject> js_object,
3944 uint32_t index,
3945 Handle<Object> value,
3946 PropertyAttributes attr) {
3947 // Normalize the elements to enable attributes on the property.
3948 NormalizeElements(js_object);
3949 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
3950 // Make sure that we never go back to fast case.
3951 dictionary->set_requires_slow_elements();
3952 PropertyDetails details = PropertyDetails(attr, NORMAL);
3953 Handle<NumberDictionary> extended_dictionary =
3954 NumberDictionarySet(dictionary, index, value, details);
3955 if (*extended_dictionary != *dictionary) {
3956 js_object->set_elements(*extended_dictionary);
3957 }
3958 return *value;
3959}
3960
3961
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003962MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
3963 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003964 Handle<Object> key,
3965 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003966 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003967 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003968 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003969
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003970 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003971 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003972 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003973 isolate->factory()->NewTypeError("non_object_property_store",
3974 HandleVector(args, 2));
3975 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003976 }
3977
3978 // If the object isn't a JavaScript object, we ignore the store.
3979 if (!object->IsJSObject()) return *value;
3980
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003981 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3982
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003983 // Check if the given key is an array index.
3984 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003985 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003986 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3987 // of a string using [] notation. We need to support this too in
3988 // JavaScript.
3989 // In the case of a String object we just need to redirect the assignment to
3990 // the underlying string if the index is in range. Since the underlying
3991 // string does nothing with the assignment then we can ignore such
3992 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003993 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003994 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003995 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003996
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003997 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
3998 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
3999 }
4000
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004001 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004002 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004003 return *value;
4004 }
4005
4006 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004007 Handle<Object> result;
4008 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004009 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4010 return NormalizeObjectSetElement(isolate,
4011 js_object,
4012 index,
4013 value,
4014 attr);
4015 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004016 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004017 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004018 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004019 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004020 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004021 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004022 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004023 return *value;
4024 }
4025
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004026 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004027 bool has_pending_exception = false;
4028 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4029 if (has_pending_exception) return Failure::Exception();
4030 Handle<String> name = Handle<String>::cast(converted);
4031
4032 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004033 return js_object->SetElement(index, *value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004034 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004035 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004036 }
4037}
4038
4039
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004040MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4041 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004042 Handle<Object> key,
4043 Handle<Object> value,
4044 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004045 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004046
4047 // Check if the given key is an array index.
4048 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004049 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004050 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4051 // of a string using [] notation. We need to support this too in
4052 // JavaScript.
4053 // In the case of a String object we just need to redirect the assignment to
4054 // the underlying string if the index is in range. Since the underlying
4055 // string does nothing with the assignment then we can ignore such
4056 // assignments.
4057 if (js_object->IsStringObjectWithCharacterAt(index)) {
4058 return *value;
4059 }
4060
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004061 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004062 }
4063
4064 if (key->IsString()) {
4065 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004066 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004067 } else {
4068 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004069 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004070 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4071 *value,
4072 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004073 }
4074 }
4075
4076 // Call-back into JavaScript to convert the key to a string.
4077 bool has_pending_exception = false;
4078 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4079 if (has_pending_exception) return Failure::Exception();
4080 Handle<String> name = Handle<String>::cast(converted);
4081
4082 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004083 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004084 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004085 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004086 }
4087}
4088
4089
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004090MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4091 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004092 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004093 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004094
4095 // Check if the given key is an array index.
4096 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004097 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004098 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4099 // characters of a string using [] notation. In the case of a
4100 // String object we just need to redirect the deletion to the
4101 // underlying string if the index is in range. Since the
4102 // underlying string does nothing with the deletion, we can ignore
4103 // such deletions.
4104 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004105 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004106 }
4107
4108 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4109 }
4110
4111 Handle<String> key_string;
4112 if (key->IsString()) {
4113 key_string = Handle<String>::cast(key);
4114 } else {
4115 // Call-back into JavaScript to convert the key to a string.
4116 bool has_pending_exception = false;
4117 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4118 if (has_pending_exception) return Failure::Exception();
4119 key_string = Handle<String>::cast(converted);
4120 }
4121
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004122 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004123 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4124}
4125
4126
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004127RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004128 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004129 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004130
4131 Handle<Object> object = args.at<Object>(0);
4132 Handle<Object> key = args.at<Object>(1);
4133 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004134 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004135 RUNTIME_ASSERT(
4136 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004137 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004138 PropertyAttributes attributes =
4139 static_cast<PropertyAttributes>(unchecked_attributes);
4140
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004141 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004142 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004143 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004144 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4145 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004146 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004147 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004148
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004149 return Runtime::SetObjectProperty(isolate,
4150 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004151 key,
4152 value,
4153 attributes,
4154 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004155}
4156
4157
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004158// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004159// This is used to decide if we should transform null and undefined
4160// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004161RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004162 NoHandleAllocation ha;
4163 RUNTIME_ASSERT(args.length() == 1);
4164
4165 Handle<Object> object = args.at<Object>(0);
4166
4167 if (object->IsJSFunction()) {
4168 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004169 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004170 }
4171 return isolate->heap()->undefined_value();
4172}
4173
4174
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004175// Set a local property, even if it is READ_ONLY. If the property does not
4176// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004177RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004178 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004179 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004180 CONVERT_CHECKED(JSObject, object, args[0]);
4181 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004182 // Compute attributes.
4183 PropertyAttributes attributes = NONE;
4184 if (args.length() == 4) {
4185 CONVERT_CHECKED(Smi, value_obj, args[3]);
4186 int unchecked_value = value_obj->value();
4187 // Only attribute bits should be set.
4188 RUNTIME_ASSERT(
4189 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4190 attributes = static_cast<PropertyAttributes>(unchecked_value);
4191 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004192
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004193 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004194 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004195}
4196
4197
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004198RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004199 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004200 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004201
4202 CONVERT_CHECKED(JSObject, object, args[0]);
4203 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004204 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004205 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004206 ? JSObject::STRICT_DELETION
4207 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004208}
4209
4210
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004211static Object* HasLocalPropertyImplementation(Isolate* isolate,
4212 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004213 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004214 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004215 // Handle hidden prototypes. If there's a hidden prototype above this thing
4216 // then we have to check it for properties, because they are supposed to
4217 // look like they are on this object.
4218 Handle<Object> proto(object->GetPrototype());
4219 if (proto->IsJSObject() &&
4220 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004221 return HasLocalPropertyImplementation(isolate,
4222 Handle<JSObject>::cast(proto),
4223 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004224 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004225 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004226}
4227
4228
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004229RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004230 NoHandleAllocation ha;
4231 ASSERT(args.length() == 2);
4232 CONVERT_CHECKED(String, key, args[1]);
4233
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004234 uint32_t index;
4235 const bool key_is_array_index = key->AsArrayIndex(&index);
4236
ager@chromium.org9085a012009-05-11 19:22:57 +00004237 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004238 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004239 if (obj->IsJSObject()) {
4240 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004241 // Fast case: either the key is a real named property or it is not
4242 // an array index and there are no interceptors or hidden
4243 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004244 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004245 Map* map = object->map();
4246 if (!key_is_array_index &&
4247 !map->has_named_interceptor() &&
4248 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4249 return isolate->heap()->false_value();
4250 }
4251 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004252 HandleScope scope(isolate);
4253 return HasLocalPropertyImplementation(isolate,
4254 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004255 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004256 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004257 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004258 String* string = String::cast(obj);
4259 if (index < static_cast<uint32_t>(string->length())) {
4260 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004261 }
4262 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004263 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004264}
4265
4266
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004267RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004268 NoHandleAllocation na;
4269 ASSERT(args.length() == 2);
4270
4271 // Only JS objects can have properties.
4272 if (args[0]->IsJSObject()) {
4273 JSObject* object = JSObject::cast(args[0]);
4274 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004275 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004276 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004277 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004278}
4279
4280
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004281RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004282 NoHandleAllocation na;
4283 ASSERT(args.length() == 2);
4284
4285 // Only JS objects can have elements.
4286 if (args[0]->IsJSObject()) {
4287 JSObject* object = JSObject::cast(args[0]);
4288 CONVERT_CHECKED(Smi, index_obj, args[1]);
4289 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004290 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004291 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004292 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004293}
4294
4295
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004296RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004297 NoHandleAllocation ha;
4298 ASSERT(args.length() == 2);
4299
4300 CONVERT_CHECKED(JSObject, object, args[0]);
4301 CONVERT_CHECKED(String, key, args[1]);
4302
4303 uint32_t index;
4304 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004305 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004306 }
4307
ager@chromium.org870a0b62008-11-04 11:43:05 +00004308 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004309 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004310}
4311
4312
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004313RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004314 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004315 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004316 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004317 return *GetKeysFor(object);
4318}
4319
4320
4321// Returns either a FixedArray as Runtime_GetPropertyNames,
4322// or, if the given object has an enum cache that contains
4323// all enumerable properties of the object and its prototypes
4324// have none, the map of the object. This is used to speed up
4325// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004326RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004327 ASSERT(args.length() == 1);
4328
4329 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4330
4331 if (raw_object->IsSimpleEnum()) return raw_object->map();
4332
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004333 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004334 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004335 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4336 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004337
4338 // Test again, since cache may have been built by preceding call.
4339 if (object->IsSimpleEnum()) return object->map();
4340
4341 return *content;
4342}
4343
4344
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004345// Find the length of the prototype chain that is to to handled as one. If a
4346// prototype object is hidden it is to be viewed as part of the the object it
4347// is prototype for.
4348static int LocalPrototypeChainLength(JSObject* obj) {
4349 int count = 1;
4350 Object* proto = obj->GetPrototype();
4351 while (proto->IsJSObject() &&
4352 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4353 count++;
4354 proto = JSObject::cast(proto)->GetPrototype();
4355 }
4356 return count;
4357}
4358
4359
4360// Return the names of the local named properties.
4361// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004362RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004363 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004364 ASSERT(args.length() == 1);
4365 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004366 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004367 }
4368 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4369
4370 // Skip the global proxy as it has no properties and always delegates to the
4371 // real global object.
4372 if (obj->IsJSGlobalProxy()) {
4373 // Only collect names if access is permitted.
4374 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004375 !isolate->MayNamedAccess(*obj,
4376 isolate->heap()->undefined_value(),
4377 v8::ACCESS_KEYS)) {
4378 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4379 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004380 }
4381 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4382 }
4383
4384 // Find the number of objects making up this.
4385 int length = LocalPrototypeChainLength(*obj);
4386
4387 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004388 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004389 int total_property_count = 0;
4390 Handle<JSObject> jsproto = obj;
4391 for (int i = 0; i < length; i++) {
4392 // Only collect names if access is permitted.
4393 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004394 !isolate->MayNamedAccess(*jsproto,
4395 isolate->heap()->undefined_value(),
4396 v8::ACCESS_KEYS)) {
4397 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4398 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004399 }
4400 int n;
4401 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4402 local_property_count[i] = n;
4403 total_property_count += n;
4404 if (i < length - 1) {
4405 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4406 }
4407 }
4408
4409 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004410 Handle<FixedArray> names =
4411 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004412
4413 // Get the property names.
4414 jsproto = obj;
4415 int proto_with_hidden_properties = 0;
4416 for (int i = 0; i < length; i++) {
4417 jsproto->GetLocalPropertyNames(*names,
4418 i == 0 ? 0 : local_property_count[i - 1]);
4419 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4420 proto_with_hidden_properties++;
4421 }
4422 if (i < length - 1) {
4423 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4424 }
4425 }
4426
4427 // Filter out name of hidden propeties object.
4428 if (proto_with_hidden_properties > 0) {
4429 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004430 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004431 names->length() - proto_with_hidden_properties);
4432 int dest_pos = 0;
4433 for (int i = 0; i < total_property_count; i++) {
4434 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004435 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004436 continue;
4437 }
4438 names->set(dest_pos++, name);
4439 }
4440 }
4441
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004442 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004443}
4444
4445
4446// Return the names of the local indexed properties.
4447// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004448RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004449 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004450 ASSERT(args.length() == 1);
4451 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004452 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004453 }
4454 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4455
4456 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004457 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004458 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004459 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004460}
4461
4462
4463// Return information on whether an object has a named or indexed interceptor.
4464// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004465RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004466 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004467 ASSERT(args.length() == 1);
4468 if (!args[0]->IsJSObject()) {
4469 return Smi::FromInt(0);
4470 }
4471 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4472
4473 int result = 0;
4474 if (obj->HasNamedInterceptor()) result |= 2;
4475 if (obj->HasIndexedInterceptor()) result |= 1;
4476
4477 return Smi::FromInt(result);
4478}
4479
4480
4481// Return property names from named interceptor.
4482// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004483RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004484 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004485 ASSERT(args.length() == 1);
4486 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4487
4488 if (obj->HasNamedInterceptor()) {
4489 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4490 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4491 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004492 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004493}
4494
4495
4496// Return element names from indexed interceptor.
4497// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004498RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004499 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004500 ASSERT(args.length() == 1);
4501 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4502
4503 if (obj->HasIndexedInterceptor()) {
4504 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4505 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4506 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004507 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004508}
4509
4510
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004511RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004512 ASSERT_EQ(args.length(), 1);
4513 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004514 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004515 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004516
4517 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004518 // Do access checks before going to the global object.
4519 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004520 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004521 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004522 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4523 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004524 }
4525
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004526 Handle<Object> proto(object->GetPrototype());
4527 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004528 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004529 object = Handle<JSObject>::cast(proto);
4530 }
4531
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004532 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4533 LOCAL_ONLY);
4534 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4535 // property array and since the result is mutable we have to create
4536 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004537 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004538 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004539 for (int i = 0; i < length; i++) {
4540 Object* entry = contents->get(i);
4541 if (entry->IsString()) {
4542 copy->set(i, entry);
4543 } else {
4544 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004545 HandleScope scope(isolate);
4546 Handle<Object> entry_handle(entry, isolate);
4547 Handle<Object> entry_str =
4548 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004549 copy->set(i, *entry_str);
4550 }
4551 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004552 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004553}
4554
4555
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004556RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004557 NoHandleAllocation ha;
4558 ASSERT(args.length() == 1);
4559
4560 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004561 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004562 it.AdvanceToArgumentsFrame();
4563 JavaScriptFrame* frame = it.frame();
4564
4565 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004566 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004567
4568 // Try to convert the key to an index. If successful and within
4569 // index return the the argument from the frame.
4570 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004571 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004572 return frame->GetParameter(index);
4573 }
4574
4575 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004576 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004577 bool exception = false;
4578 Handle<Object> converted =
4579 Execution::ToString(args.at<Object>(0), &exception);
4580 if (exception) return Failure::Exception();
4581 Handle<String> key = Handle<String>::cast(converted);
4582
4583 // Try to convert the string key into an array index.
4584 if (key->AsArrayIndex(&index)) {
4585 if (index < n) {
4586 return frame->GetParameter(index);
4587 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004588 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004589 }
4590 }
4591
4592 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004593 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4594 if (key->Equals(isolate->heap()->callee_symbol())) {
4595 Object* function = frame->function();
4596 if (function->IsJSFunction() &&
4597 JSFunction::cast(function)->shared()->strict_mode()) {
4598 return isolate->Throw(*isolate->factory()->NewTypeError(
4599 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4600 }
4601 return function;
4602 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603
4604 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004605 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004606}
4607
4608
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004609RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004610 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004611
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004612 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004613 Handle<Object> object = args.at<Object>(0);
4614 if (object->IsJSObject()) {
4615 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004616 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004617 MaybeObject* ok = js_object->TransformToFastProperties(0);
4618 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004619 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004620 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004621 return *object;
4622}
4623
4624
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004625RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004626 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004627
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004628 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004629 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004630 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004631 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004632 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004633 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004634 return *object;
4635}
4636
4637
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004638RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004639 NoHandleAllocation ha;
4640 ASSERT(args.length() == 1);
4641
4642 return args[0]->ToBoolean();
4643}
4644
4645
4646// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4647// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004648RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004649 NoHandleAllocation ha;
4650
4651 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004652 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004653 HeapObject* heap_obj = HeapObject::cast(obj);
4654
4655 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004656 if (heap_obj->map()->is_undetectable()) {
4657 return isolate->heap()->undefined_symbol();
4658 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004659
4660 InstanceType instance_type = heap_obj->map()->instance_type();
4661 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004662 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004663 }
4664
4665 switch (instance_type) {
4666 case ODDBALL_TYPE:
4667 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004668 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004669 }
4670 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004671 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004672 }
4673 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004674 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004675 case JS_FUNCTION_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004676 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004677 default:
4678 // For any kind of object not handled above, the spec rule for
4679 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004680 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004681 }
4682}
4683
4684
lrn@chromium.org25156de2010-04-06 13:10:27 +00004685static bool AreDigits(const char*s, int from, int to) {
4686 for (int i = from; i < to; i++) {
4687 if (s[i] < '0' || s[i] > '9') return false;
4688 }
4689
4690 return true;
4691}
4692
4693
4694static int ParseDecimalInteger(const char*s, int from, int to) {
4695 ASSERT(to - from < 10); // Overflow is not possible.
4696 ASSERT(from < to);
4697 int d = s[from] - '0';
4698
4699 for (int i = from + 1; i < to; i++) {
4700 d = 10 * d + (s[i] - '0');
4701 }
4702
4703 return d;
4704}
4705
4706
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004707RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004708 NoHandleAllocation ha;
4709 ASSERT(args.length() == 1);
4710 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004711 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004712
4713 // Fast case: short integer or some sorts of junk values.
4714 int len = subject->length();
4715 if (subject->IsSeqAsciiString()) {
4716 if (len == 0) return Smi::FromInt(0);
4717
4718 char const* data = SeqAsciiString::cast(subject)->GetChars();
4719 bool minus = (data[0] == '-');
4720 int start_pos = (minus ? 1 : 0);
4721
4722 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004723 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004724 } else if (data[start_pos] > '9') {
4725 // Fast check for a junk value. A valid string may start from a
4726 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4727 // the 'I' character ('Infinity'). All of that have codes not greater than
4728 // '9' except 'I'.
4729 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004730 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004731 }
4732 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4733 // The maximal/minimal smi has 10 digits. If the string has less digits we
4734 // know it will fit into the smi-data type.
4735 int d = ParseDecimalInteger(data, start_pos, len);
4736 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004737 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004738 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004739 } else if (!subject->HasHashCode() &&
4740 len <= String::kMaxArrayIndexSize &&
4741 (len == 1 || data[0] != '0')) {
4742 // String hash is not calculated yet but all the data are present.
4743 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004744 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004745#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004746 subject->Hash(); // Force hash calculation.
4747 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4748 static_cast<int>(hash));
4749#endif
4750 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004751 }
4752 return Smi::FromInt(d);
4753 }
4754 }
4755
4756 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004757 return isolate->heap()->NumberFromDouble(
4758 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004759}
4760
4761
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004762RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004763 NoHandleAllocation ha;
4764 ASSERT(args.length() == 1);
4765
4766 CONVERT_CHECKED(JSArray, codes, args[0]);
4767 int length = Smi::cast(codes->length())->value();
4768
4769 // Check if the string can be ASCII.
4770 int i;
4771 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004772 Object* element;
4773 { MaybeObject* maybe_element = codes->GetElement(i);
4774 // We probably can't get an exception here, but just in order to enforce
4775 // the checking of inputs in the runtime calls we check here.
4776 if (!maybe_element->ToObject(&element)) return maybe_element;
4777 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004778 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4779 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4780 break;
4781 }
4782
lrn@chromium.org303ada72010-10-27 09:33:13 +00004783 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004784 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004785 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004786 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004787 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004788 }
4789
lrn@chromium.org303ada72010-10-27 09:33:13 +00004790 Object* object = NULL;
4791 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004792 String* result = String::cast(object);
4793 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004794 Object* element;
4795 { MaybeObject* maybe_element = codes->GetElement(i);
4796 if (!maybe_element->ToObject(&element)) return maybe_element;
4797 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004798 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004799 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004800 }
4801 return result;
4802}
4803
4804
4805// kNotEscaped is generated by the following:
4806//
4807// #!/bin/perl
4808// for (my $i = 0; $i < 256; $i++) {
4809// print "\n" if $i % 16 == 0;
4810// my $c = chr($i);
4811// my $escaped = 1;
4812// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4813// print $escaped ? "0, " : "1, ";
4814// }
4815
4816
4817static bool IsNotEscaped(uint16_t character) {
4818 // Only for 8 bit characters, the rest are always escaped (in a different way)
4819 ASSERT(character < 256);
4820 static const char kNotEscaped[256] = {
4821 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4822 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4823 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4824 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4825 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4826 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4827 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4828 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4829 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4830 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4831 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4832 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4833 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4834 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4835 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4836 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4837 };
4838 return kNotEscaped[character] != 0;
4839}
4840
4841
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004842RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004843 const char hex_chars[] = "0123456789ABCDEF";
4844 NoHandleAllocation ha;
4845 ASSERT(args.length() == 1);
4846 CONVERT_CHECKED(String, source, args[0]);
4847
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004848 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004849
4850 int escaped_length = 0;
4851 int length = source->length();
4852 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004853 Access<StringInputBuffer> buffer(
4854 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004855 buffer->Reset(source);
4856 while (buffer->has_more()) {
4857 uint16_t character = buffer->GetNext();
4858 if (character >= 256) {
4859 escaped_length += 6;
4860 } else if (IsNotEscaped(character)) {
4861 escaped_length++;
4862 } else {
4863 escaped_length += 3;
4864 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004865 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004866 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004867 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004868 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004869 return Failure::OutOfMemoryException();
4870 }
4871 }
4872 }
4873 // No length change implies no change. Return original string if no change.
4874 if (escaped_length == length) {
4875 return source;
4876 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004877 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004878 { MaybeObject* maybe_o =
4879 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004880 if (!maybe_o->ToObject(&o)) return maybe_o;
4881 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004882 String* destination = String::cast(o);
4883 int dest_position = 0;
4884
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004885 Access<StringInputBuffer> buffer(
4886 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004887 buffer->Rewind();
4888 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004889 uint16_t chr = buffer->GetNext();
4890 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004891 destination->Set(dest_position, '%');
4892 destination->Set(dest_position+1, 'u');
4893 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4894 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4895 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4896 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004897 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004898 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004899 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004900 dest_position++;
4901 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004902 destination->Set(dest_position, '%');
4903 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4904 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004905 dest_position += 3;
4906 }
4907 }
4908 return destination;
4909}
4910
4911
4912static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4913 static const signed char kHexValue['g'] = {
4914 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4915 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4916 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4917 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4918 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4919 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4920 -1, 10, 11, 12, 13, 14, 15 };
4921
4922 if (character1 > 'f') return -1;
4923 int hi = kHexValue[character1];
4924 if (hi == -1) return -1;
4925 if (character2 > 'f') return -1;
4926 int lo = kHexValue[character2];
4927 if (lo == -1) return -1;
4928 return (hi << 4) + lo;
4929}
4930
4931
ager@chromium.org870a0b62008-11-04 11:43:05 +00004932static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004933 int i,
4934 int length,
4935 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004936 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004937 int32_t hi = 0;
4938 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004939 if (character == '%' &&
4940 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004941 source->Get(i + 1) == 'u' &&
4942 (hi = TwoDigitHex(source->Get(i + 2),
4943 source->Get(i + 3))) != -1 &&
4944 (lo = TwoDigitHex(source->Get(i + 4),
4945 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004946 *step = 6;
4947 return (hi << 8) + lo;
4948 } else if (character == '%' &&
4949 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004950 (lo = TwoDigitHex(source->Get(i + 1),
4951 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004952 *step = 3;
4953 return lo;
4954 } else {
4955 *step = 1;
4956 return character;
4957 }
4958}
4959
4960
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004961RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004962 NoHandleAllocation ha;
4963 ASSERT(args.length() == 1);
4964 CONVERT_CHECKED(String, source, args[0]);
4965
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004966 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004967
4968 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004969 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004970
4971 int unescaped_length = 0;
4972 for (int i = 0; i < length; unescaped_length++) {
4973 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004974 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004975 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004976 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004977 i += step;
4978 }
4979
4980 // No length change implies no change. Return original string if no change.
4981 if (unescaped_length == length)
4982 return source;
4983
lrn@chromium.org303ada72010-10-27 09:33:13 +00004984 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004985 { MaybeObject* maybe_o =
4986 ascii ?
4987 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
4988 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004989 if (!maybe_o->ToObject(&o)) return maybe_o;
4990 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004991 String* destination = String::cast(o);
4992
4993 int dest_position = 0;
4994 for (int i = 0; i < length; dest_position++) {
4995 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004996 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004997 i += step;
4998 }
4999 return destination;
5000}
5001
5002
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005003static const unsigned int kQuoteTableLength = 128u;
5004
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005005static const int kJsonQuotesCharactersPerEntry = 8;
5006static const char* const JsonQuotes =
5007 "\\u0000 \\u0001 \\u0002 \\u0003 "
5008 "\\u0004 \\u0005 \\u0006 \\u0007 "
5009 "\\b \\t \\n \\u000b "
5010 "\\f \\r \\u000e \\u000f "
5011 "\\u0010 \\u0011 \\u0012 \\u0013 "
5012 "\\u0014 \\u0015 \\u0016 \\u0017 "
5013 "\\u0018 \\u0019 \\u001a \\u001b "
5014 "\\u001c \\u001d \\u001e \\u001f "
5015 " ! \\\" # "
5016 "$ % & ' "
5017 "( ) * + "
5018 ", - . / "
5019 "0 1 2 3 "
5020 "4 5 6 7 "
5021 "8 9 : ; "
5022 "< = > ? "
5023 "@ A B C "
5024 "D E F G "
5025 "H I J K "
5026 "L M N O "
5027 "P Q R S "
5028 "T U V W "
5029 "X Y Z [ "
5030 "\\\\ ] ^ _ "
5031 "` a b c "
5032 "d e f g "
5033 "h i j k "
5034 "l m n o "
5035 "p q r s "
5036 "t u v w "
5037 "x y z { "
5038 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005039
5040
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005041// For a string that is less than 32k characters it should always be
5042// possible to allocate it in new space.
5043static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5044
5045
5046// Doing JSON quoting cannot make the string more than this many times larger.
5047static const int kJsonQuoteWorstCaseBlowup = 6;
5048
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005049static const int kSpaceForQuotesAndComma = 3;
5050static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005051
5052// Covers the entire ASCII range (all other characters are unchanged by JSON
5053// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005054static const byte JsonQuoteLengths[kQuoteTableLength] = {
5055 6, 6, 6, 6, 6, 6, 6, 6,
5056 2, 2, 2, 6, 2, 2, 6, 6,
5057 6, 6, 6, 6, 6, 6, 6, 6,
5058 6, 6, 6, 6, 6, 6, 6, 6,
5059 1, 1, 2, 1, 1, 1, 1, 1,
5060 1, 1, 1, 1, 1, 1, 1, 1,
5061 1, 1, 1, 1, 1, 1, 1, 1,
5062 1, 1, 1, 1, 1, 1, 1, 1,
5063 1, 1, 1, 1, 1, 1, 1, 1,
5064 1, 1, 1, 1, 1, 1, 1, 1,
5065 1, 1, 1, 1, 1, 1, 1, 1,
5066 1, 1, 1, 1, 2, 1, 1, 1,
5067 1, 1, 1, 1, 1, 1, 1, 1,
5068 1, 1, 1, 1, 1, 1, 1, 1,
5069 1, 1, 1, 1, 1, 1, 1, 1,
5070 1, 1, 1, 1, 1, 1, 1, 1,
5071};
5072
5073
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005074template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005075MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005076
5077
5078template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005079MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5080 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005081}
5082
5083
5084template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005085MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5086 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005087}
5088
5089
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005090template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005091static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5092 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005093 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005094 const Char* read_cursor = characters.start();
5095 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005096 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005097 int quoted_length = kSpaceForQuotes;
5098 while (read_cursor < end) {
5099 Char c = *(read_cursor++);
5100 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5101 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005102 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005103 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005104 }
5105 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005106 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5107 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005108 Object* new_object;
5109 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005110 return new_alloc;
5111 }
5112 StringType* new_string = StringType::cast(new_object);
5113
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005114 Char* write_cursor = reinterpret_cast<Char*>(
5115 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005116 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005117 *(write_cursor++) = '"';
5118
5119 read_cursor = characters.start();
5120 while (read_cursor < end) {
5121 Char c = *(read_cursor++);
5122 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5123 *(write_cursor++) = c;
5124 } else {
5125 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5126 const char* replacement = JsonQuotes +
5127 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5128 for (int i = 0; i < len; i++) {
5129 *write_cursor++ = *replacement++;
5130 }
5131 }
5132 }
5133 *(write_cursor++) = '"';
5134 return new_string;
5135}
5136
5137
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005138template <typename SinkChar, typename SourceChar>
5139static inline SinkChar* WriteQuoteJsonString(
5140 Isolate* isolate,
5141 SinkChar* write_cursor,
5142 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005143 // SinkChar is only char if SourceChar is guaranteed to be char.
5144 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005145 const SourceChar* read_cursor = characters.start();
5146 const SourceChar* end = read_cursor + characters.length();
5147 *(write_cursor++) = '"';
5148 while (read_cursor < end) {
5149 SourceChar c = *(read_cursor++);
5150 if (sizeof(SourceChar) > 1u &&
5151 static_cast<unsigned>(c) >= kQuoteTableLength) {
5152 *(write_cursor++) = static_cast<SinkChar>(c);
5153 } else {
5154 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5155 const char* replacement = JsonQuotes +
5156 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5157 write_cursor[0] = replacement[0];
5158 if (len > 1) {
5159 write_cursor[1] = replacement[1];
5160 if (len > 2) {
5161 ASSERT(len == 6);
5162 write_cursor[2] = replacement[2];
5163 write_cursor[3] = replacement[3];
5164 write_cursor[4] = replacement[4];
5165 write_cursor[5] = replacement[5];
5166 }
5167 }
5168 write_cursor += len;
5169 }
5170 }
5171 *(write_cursor++) = '"';
5172 return write_cursor;
5173}
5174
5175
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005176template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005177static MaybeObject* QuoteJsonString(Isolate* isolate,
5178 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005179 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005180 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005181 int worst_case_length =
5182 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005183 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005184 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005185 }
5186
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005187 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5188 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005189 Object* new_object;
5190 if (!new_alloc->ToObject(&new_object)) {
5191 return new_alloc;
5192 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005193 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005194 // Even if our string is small enough to fit in new space we still have to
5195 // handle it being allocated in old space as may happen in the third
5196 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5197 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005198 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005199 }
5200 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005201 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005202
5203 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5204 Char* write_cursor = reinterpret_cast<Char*>(
5205 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005206 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005207 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5208 write_cursor,
5209 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005210 int final_length = static_cast<int>(
5211 write_cursor - reinterpret_cast<Char*>(
5212 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005213 isolate->heap()->new_space()->
5214 template ShrinkStringAtAllocationBoundary<StringType>(
5215 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005216 return new_string;
5217}
5218
5219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005220RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005221 NoHandleAllocation ha;
5222 CONVERT_CHECKED(String, str, args[0]);
5223 if (!str->IsFlat()) {
5224 MaybeObject* try_flatten = str->TryFlatten();
5225 Object* flat;
5226 if (!try_flatten->ToObject(&flat)) {
5227 return try_flatten;
5228 }
5229 str = String::cast(flat);
5230 ASSERT(str->IsFlat());
5231 }
5232 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005233 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5234 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005235 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005236 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5237 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005238 }
5239}
5240
5241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005242RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005243 NoHandleAllocation ha;
5244 CONVERT_CHECKED(String, str, args[0]);
5245 if (!str->IsFlat()) {
5246 MaybeObject* try_flatten = str->TryFlatten();
5247 Object* flat;
5248 if (!try_flatten->ToObject(&flat)) {
5249 return try_flatten;
5250 }
5251 str = String::cast(flat);
5252 ASSERT(str->IsFlat());
5253 }
5254 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005255 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5256 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005257 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005258 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5259 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005260 }
5261}
5262
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005263
5264template <typename Char, typename StringType>
5265static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5266 FixedArray* array,
5267 int worst_case_length) {
5268 int length = array->length();
5269
5270 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5271 worst_case_length);
5272 Object* new_object;
5273 if (!new_alloc->ToObject(&new_object)) {
5274 return new_alloc;
5275 }
5276 if (!isolate->heap()->new_space()->Contains(new_object)) {
5277 // Even if our string is small enough to fit in new space we still have to
5278 // handle it being allocated in old space as may happen in the third
5279 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5280 // CEntryStub::GenerateCore.
5281 return isolate->heap()->undefined_value();
5282 }
5283 AssertNoAllocation no_gc;
5284 StringType* new_string = StringType::cast(new_object);
5285 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5286
5287 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5288 Char* write_cursor = reinterpret_cast<Char*>(
5289 new_string->address() + SeqAsciiString::kHeaderSize);
5290 *(write_cursor++) = '[';
5291 for (int i = 0; i < length; i++) {
5292 if (i != 0) *(write_cursor++) = ',';
5293 String* str = String::cast(array->get(i));
5294 if (str->IsTwoByteRepresentation()) {
5295 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5296 write_cursor,
5297 str->ToUC16Vector());
5298 } else {
5299 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5300 write_cursor,
5301 str->ToAsciiVector());
5302 }
5303 }
5304 *(write_cursor++) = ']';
5305
5306 int final_length = static_cast<int>(
5307 write_cursor - reinterpret_cast<Char*>(
5308 new_string->address() + SeqAsciiString::kHeaderSize));
5309 isolate->heap()->new_space()->
5310 template ShrinkStringAtAllocationBoundary<StringType>(
5311 new_string, final_length);
5312 return new_string;
5313}
5314
5315
5316RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5317 NoHandleAllocation ha;
5318 ASSERT(args.length() == 1);
5319 CONVERT_CHECKED(JSArray, array, args[0]);
5320
5321 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5322 FixedArray* elements = FixedArray::cast(array->elements());
5323 int n = elements->length();
5324 bool ascii = true;
5325 int total_length = 0;
5326
5327 for (int i = 0; i < n; i++) {
5328 Object* elt = elements->get(i);
5329 if (!elt->IsString()) return isolate->heap()->undefined_value();
5330 String* element = String::cast(elt);
5331 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5332 total_length += element->length();
5333 if (ascii && element->IsTwoByteRepresentation()) {
5334 ascii = false;
5335 }
5336 }
5337
5338 int worst_case_length =
5339 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5340 + total_length * kJsonQuoteWorstCaseBlowup;
5341
5342 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5343 return isolate->heap()->undefined_value();
5344 }
5345
5346 if (ascii) {
5347 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5348 elements,
5349 worst_case_length);
5350 } else {
5351 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5352 elements,
5353 worst_case_length);
5354 }
5355}
5356
5357
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005358RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005359 NoHandleAllocation ha;
5360
5361 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005362 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005363
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005364 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005365
lrn@chromium.org25156de2010-04-06 13:10:27 +00005366 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005367 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005368 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005369}
5370
5371
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005372RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005373 NoHandleAllocation ha;
5374 CONVERT_CHECKED(String, str, args[0]);
5375
5376 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005377 double value = StringToDouble(isolate->unicode_cache(),
5378 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005379
5380 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005381 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005382}
5383
5384
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005385template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005386MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005387 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005388 String* s,
5389 int length,
5390 int input_string_length,
5391 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005392 // We try this twice, once with the assumption that the result is no longer
5393 // than the input and, if that assumption breaks, again with the exact
5394 // length. This may not be pretty, but it is nicer than what was here before
5395 // and I hereby claim my vaffel-is.
5396 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005397 // Allocate the resulting string.
5398 //
5399 // NOTE: This assumes that the upper/lower case of an ascii
5400 // character is also ascii. This is currently the case, but it
5401 // might break in the future if we implement more context and locale
5402 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005403 Object* o;
5404 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005405 ? isolate->heap()->AllocateRawAsciiString(length)
5406 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005407 if (!maybe_o->ToObject(&o)) return maybe_o;
5408 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005409 String* result = String::cast(o);
5410 bool has_changed_character = false;
5411
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005412 // Convert all characters to upper case, assuming that they will fit
5413 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005414 Access<StringInputBuffer> buffer(
5415 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005416 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005417 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005418 // We can assume that the string is not empty
5419 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005420 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005421 bool has_next = buffer->has_more();
5422 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005423 int char_length = mapping->get(current, next, chars);
5424 if (char_length == 0) {
5425 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005426 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005427 i++;
5428 } else if (char_length == 1) {
5429 // Common case: converting the letter resulted in one character.
5430 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005431 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005432 has_changed_character = true;
5433 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005434 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005435 // We've assumed that the result would be as long as the
5436 // input but here is a character that converts to several
5437 // characters. No matter, we calculate the exact length
5438 // of the result and try the whole thing again.
5439 //
5440 // Note that this leaves room for optimization. We could just
5441 // memcpy what we already have to the result string. Also,
5442 // the result string is the last object allocated we could
5443 // "realloc" it and probably, in the vast majority of cases,
5444 // extend the existing string to be able to hold the full
5445 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005446 int next_length = 0;
5447 if (has_next) {
5448 next_length = mapping->get(next, 0, chars);
5449 if (next_length == 0) next_length = 1;
5450 }
5451 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005452 while (buffer->has_more()) {
5453 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005454 // NOTE: we use 0 as the next character here because, while
5455 // the next character may affect what a character converts to,
5456 // it does not in any case affect the length of what it convert
5457 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005458 int char_length = mapping->get(current, 0, chars);
5459 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005460 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005461 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005462 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005463 return Failure::OutOfMemoryException();
5464 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005465 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005466 // Try again with the real length.
5467 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005468 } else {
5469 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005470 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005471 i++;
5472 }
5473 has_changed_character = true;
5474 }
5475 current = next;
5476 }
5477 if (has_changed_character) {
5478 return result;
5479 } else {
5480 // If we didn't actually change anything in doing the conversion
5481 // we simple return the result and let the converted string
5482 // become garbage; there is no reason to keep two identical strings
5483 // alive.
5484 return s;
5485 }
5486}
5487
5488
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005489namespace {
5490
lrn@chromium.org303ada72010-10-27 09:33:13 +00005491static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5492
5493
5494// Given a word and two range boundaries returns a word with high bit
5495// set in every byte iff the corresponding input byte was strictly in
5496// the range (m, n). All the other bits in the result are cleared.
5497// This function is only useful when it can be inlined and the
5498// boundaries are statically known.
5499// Requires: all bytes in the input word and the boundaries must be
5500// ascii (less than 0x7F).
5501static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5502 // Every byte in an ascii string is less than or equal to 0x7F.
5503 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5504 // Use strict inequalities since in edge cases the function could be
5505 // further simplified.
5506 ASSERT(0 < m && m < n && n < 0x7F);
5507 // Has high bit set in every w byte less than n.
5508 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5509 // Has high bit set in every w byte greater than m.
5510 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5511 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5512}
5513
5514
5515enum AsciiCaseConversion {
5516 ASCII_TO_LOWER,
5517 ASCII_TO_UPPER
5518};
5519
5520
5521template <AsciiCaseConversion dir>
5522struct FastAsciiConverter {
5523 static bool Convert(char* dst, char* src, int length) {
5524#ifdef DEBUG
5525 char* saved_dst = dst;
5526 char* saved_src = src;
5527#endif
5528 // We rely on the distance between upper and lower case letters
5529 // being a known power of 2.
5530 ASSERT('a' - 'A' == (1 << 5));
5531 // Boundaries for the range of input characters than require conversion.
5532 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5533 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5534 bool changed = false;
5535 char* const limit = src + length;
5536#ifdef V8_HOST_CAN_READ_UNALIGNED
5537 // Process the prefix of the input that requires no conversion one
5538 // (machine) word at a time.
5539 while (src <= limit - sizeof(uintptr_t)) {
5540 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5541 if (AsciiRangeMask(w, lo, hi) != 0) {
5542 changed = true;
5543 break;
5544 }
5545 *reinterpret_cast<uintptr_t*>(dst) = w;
5546 src += sizeof(uintptr_t);
5547 dst += sizeof(uintptr_t);
5548 }
5549 // Process the remainder of the input performing conversion when
5550 // required one word at a time.
5551 while (src <= limit - sizeof(uintptr_t)) {
5552 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5553 uintptr_t m = AsciiRangeMask(w, lo, hi);
5554 // The mask has high (7th) bit set in every byte that needs
5555 // conversion and we know that the distance between cases is
5556 // 1 << 5.
5557 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5558 src += sizeof(uintptr_t);
5559 dst += sizeof(uintptr_t);
5560 }
5561#endif
5562 // Process the last few bytes of the input (or the whole input if
5563 // unaligned access is not supported).
5564 while (src < limit) {
5565 char c = *src;
5566 if (lo < c && c < hi) {
5567 c ^= (1 << 5);
5568 changed = true;
5569 }
5570 *dst = c;
5571 ++src;
5572 ++dst;
5573 }
5574#ifdef DEBUG
5575 CheckConvert(saved_dst, saved_src, length, changed);
5576#endif
5577 return changed;
5578 }
5579
5580#ifdef DEBUG
5581 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5582 bool expected_changed = false;
5583 for (int i = 0; i < length; i++) {
5584 if (dst[i] == src[i]) continue;
5585 expected_changed = true;
5586 if (dir == ASCII_TO_LOWER) {
5587 ASSERT('A' <= src[i] && src[i] <= 'Z');
5588 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5589 } else {
5590 ASSERT(dir == ASCII_TO_UPPER);
5591 ASSERT('a' <= src[i] && src[i] <= 'z');
5592 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5593 }
5594 }
5595 ASSERT(expected_changed == changed);
5596 }
5597#endif
5598};
5599
5600
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005601struct ToLowerTraits {
5602 typedef unibrow::ToLowercase UnibrowConverter;
5603
lrn@chromium.org303ada72010-10-27 09:33:13 +00005604 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005605};
5606
5607
5608struct ToUpperTraits {
5609 typedef unibrow::ToUppercase UnibrowConverter;
5610
lrn@chromium.org303ada72010-10-27 09:33:13 +00005611 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005612};
5613
5614} // namespace
5615
5616
5617template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005618MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005619 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005620 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005621 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005622 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005623 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005624 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005625
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005626 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005627 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005628 if (length == 0) return s;
5629
5630 // Simpler handling of ascii strings.
5631 //
5632 // NOTE: This assumes that the upper/lower case of an ascii
5633 // character is also ascii. This is currently the case, but it
5634 // might break in the future if we implement more context and locale
5635 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005636 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005637 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005638 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005639 if (!maybe_o->ToObject(&o)) return maybe_o;
5640 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005641 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005642 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005643 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005644 return has_changed_character ? result : s;
5645 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005646
lrn@chromium.org303ada72010-10-27 09:33:13 +00005647 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005648 { MaybeObject* maybe_answer =
5649 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005650 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5651 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005652 if (answer->IsSmi()) {
5653 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005654 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005655 ConvertCaseHelper(isolate,
5656 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005657 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5658 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005659 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005660 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005661}
5662
5663
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005664RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005665 return ConvertCase<ToLowerTraits>(
5666 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005667}
5668
5669
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005670RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005671 return ConvertCase<ToUpperTraits>(
5672 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005673}
5674
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005675
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005676static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5677 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5678}
5679
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005680
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005681RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005682 NoHandleAllocation ha;
5683 ASSERT(args.length() == 3);
5684
5685 CONVERT_CHECKED(String, s, args[0]);
5686 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5687 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5688
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005689 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005690 int length = s->length();
5691
5692 int left = 0;
5693 if (trimLeft) {
5694 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5695 left++;
5696 }
5697 }
5698
5699 int right = length;
5700 if (trimRight) {
5701 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5702 right--;
5703 }
5704 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005705 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005706}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005707
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005708
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005709template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005710void FindStringIndices(Isolate* isolate,
5711 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005712 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005713 ZoneList<int>* indices,
5714 unsigned int limit) {
5715 ASSERT(limit > 0);
5716 // Collect indices of pattern in subject, and the end-of-string index.
5717 // Stop after finding at most limit values.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005718 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005719 int pattern_length = pattern.length();
5720 int index = 0;
5721 while (limit > 0) {
5722 index = search.Search(subject, index);
5723 if (index < 0) return;
5724 indices->Add(index);
5725 index += pattern_length;
5726 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005727 }
5728}
5729
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005730
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005731RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005732 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005733 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005734 CONVERT_ARG_CHECKED(String, subject, 0);
5735 CONVERT_ARG_CHECKED(String, pattern, 1);
5736 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5737
5738 int subject_length = subject->length();
5739 int pattern_length = pattern->length();
5740 RUNTIME_ASSERT(pattern_length > 0);
5741
5742 // The limit can be very large (0xffffffffu), but since the pattern
5743 // isn't empty, we can never create more parts than ~half the length
5744 // of the subject.
5745
5746 if (!subject->IsFlat()) FlattenString(subject);
5747
5748 static const int kMaxInitialListCapacity = 16;
5749
danno@chromium.org40cb8782011-05-25 07:58:50 +00005750 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005751
5752 // Find (up to limit) indices of separator and end-of-string in subject
5753 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5754 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005755 if (!pattern->IsFlat()) FlattenString(pattern);
5756
5757 // No allocation block.
5758 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005759 AssertNoAllocation nogc;
5760 if (subject->IsAsciiRepresentation()) {
5761 Vector<const char> subject_vector = subject->ToAsciiVector();
5762 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005763 FindStringIndices(isolate,
5764 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005765 pattern->ToAsciiVector(),
5766 &indices,
5767 limit);
5768 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005769 FindStringIndices(isolate,
5770 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005771 pattern->ToUC16Vector(),
5772 &indices,
5773 limit);
5774 }
5775 } else {
5776 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5777 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005778 FindStringIndices(isolate,
5779 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005780 pattern->ToAsciiVector(),
5781 &indices,
5782 limit);
5783 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005784 FindStringIndices(isolate,
5785 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005786 pattern->ToUC16Vector(),
5787 &indices,
5788 limit);
5789 }
5790 }
5791 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005792
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005793 if (static_cast<uint32_t>(indices.length()) < limit) {
5794 indices.Add(subject_length);
5795 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005796
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005797 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005798
5799 // Create JSArray of substrings separated by separator.
5800 int part_count = indices.length();
5801
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005802 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005803 result->set_length(Smi::FromInt(part_count));
5804
5805 ASSERT(result->HasFastElements());
5806
5807 if (part_count == 1 && indices.at(0) == subject_length) {
5808 FixedArray::cast(result->elements())->set(0, *subject);
5809 return *result;
5810 }
5811
5812 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5813 int part_start = 0;
5814 for (int i = 0; i < part_count; i++) {
5815 HandleScope local_loop_handle;
5816 int part_end = indices.at(i);
5817 Handle<String> substring =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005818 isolate->factory()->NewSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005819 elements->set(i, *substring);
5820 part_start = part_end + pattern_length;
5821 }
5822
5823 return *result;
5824}
5825
5826
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005827// Copies ascii characters to the given fixed array looking up
5828// one-char strings in the cache. Gives up on the first char that is
5829// not in the cache and fills the remainder with smi zeros. Returns
5830// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005831static int CopyCachedAsciiCharsToArray(Heap* heap,
5832 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005833 FixedArray* elements,
5834 int length) {
5835 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005836 FixedArray* ascii_cache = heap->single_character_string_cache();
5837 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005838 int i;
5839 for (i = 0; i < length; ++i) {
5840 Object* value = ascii_cache->get(chars[i]);
5841 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005842 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005843 elements->set(i, value, SKIP_WRITE_BARRIER);
5844 }
5845 if (i < length) {
5846 ASSERT(Smi::FromInt(0) == 0);
5847 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5848 }
5849#ifdef DEBUG
5850 for (int j = 0; j < length; ++j) {
5851 Object* element = elements->get(j);
5852 ASSERT(element == Smi::FromInt(0) ||
5853 (element->IsString() && String::cast(element)->LooksValid()));
5854 }
5855#endif
5856 return i;
5857}
5858
5859
5860// Converts a String to JSArray.
5861// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005862RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005863 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005864 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005865 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005866 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005867
5868 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005869 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005870
5871 Handle<FixedArray> elements;
5872 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005873 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005874 { MaybeObject* maybe_obj =
5875 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005876 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5877 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005878 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005879
5880 Vector<const char> chars = s->ToAsciiVector();
5881 // Note, this will initialize all elements (not only the prefix)
5882 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005883 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5884 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005885 *elements,
5886 length);
5887
5888 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005889 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5890 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005891 }
5892 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005893 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005894 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005895 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5896 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005897 }
5898 }
5899
5900#ifdef DEBUG
5901 for (int i = 0; i < length; ++i) {
5902 ASSERT(String::cast(elements->get(i))->length() == 1);
5903 }
5904#endif
5905
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005906 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005907}
5908
5909
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005910RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005911 NoHandleAllocation ha;
5912 ASSERT(args.length() == 1);
5913 CONVERT_CHECKED(String, value, args[0]);
5914 return value->ToObject();
5915}
5916
5917
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005918bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005919 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005920 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005921 return char_length == 0;
5922}
5923
5924
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005925RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005926 NoHandleAllocation ha;
5927 ASSERT(args.length() == 1);
5928
5929 Object* number = args[0];
5930 RUNTIME_ASSERT(number->IsNumber());
5931
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005932 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005933}
5934
5935
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005936RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005937 NoHandleAllocation ha;
5938 ASSERT(args.length() == 1);
5939
5940 Object* number = args[0];
5941 RUNTIME_ASSERT(number->IsNumber());
5942
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005943 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00005944}
5945
5946
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005947RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005948 NoHandleAllocation ha;
5949 ASSERT(args.length() == 1);
5950
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005951 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005952
5953 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5954 if (number > 0 && number <= Smi::kMaxValue) {
5955 return Smi::FromInt(static_cast<int>(number));
5956 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005957 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005958}
5959
5960
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005961RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005962 NoHandleAllocation ha;
5963 ASSERT(args.length() == 1);
5964
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005965 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005966
5967 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5968 if (number > 0 && number <= Smi::kMaxValue) {
5969 return Smi::FromInt(static_cast<int>(number));
5970 }
5971
5972 double double_value = DoubleToInteger(number);
5973 // Map both -0 and +0 to +0.
5974 if (double_value == 0) double_value = 0;
5975
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005976 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005977}
5978
5979
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005980RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005981 NoHandleAllocation ha;
5982 ASSERT(args.length() == 1);
5983
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005984 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005985 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005986}
5987
5988
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005989RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005990 NoHandleAllocation ha;
5991 ASSERT(args.length() == 1);
5992
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005993 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005994
5995 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5996 if (number > 0 && number <= Smi::kMaxValue) {
5997 return Smi::FromInt(static_cast<int>(number));
5998 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005999 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006000}
6001
6002
ager@chromium.org870a0b62008-11-04 11:43:05 +00006003// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6004// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006005RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006006 NoHandleAllocation ha;
6007 ASSERT(args.length() == 1);
6008
6009 Object* obj = args[0];
6010 if (obj->IsSmi()) {
6011 return obj;
6012 }
6013 if (obj->IsHeapNumber()) {
6014 double value = HeapNumber::cast(obj)->value();
6015 int int_value = FastD2I(value);
6016 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6017 return Smi::FromInt(int_value);
6018 }
6019 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006020 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006021}
6022
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006023
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006024RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006025 NoHandleAllocation ha;
6026 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006027 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006028}
6029
6030
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006031RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006032 NoHandleAllocation ha;
6033 ASSERT(args.length() == 2);
6034
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006035 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6036 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006037 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006038}
6039
6040
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006041RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006042 NoHandleAllocation ha;
6043 ASSERT(args.length() == 2);
6044
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006045 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6046 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006047 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006048}
6049
6050
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006051RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006052 NoHandleAllocation ha;
6053 ASSERT(args.length() == 2);
6054
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006055 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6056 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006057 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006058}
6059
6060
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006061RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006062 NoHandleAllocation ha;
6063 ASSERT(args.length() == 1);
6064
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006065 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006066 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006067}
6068
6069
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006070RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006071 NoHandleAllocation ha;
6072 ASSERT(args.length() == 0);
6073
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006074 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006075}
6076
6077
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006078RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006079 NoHandleAllocation ha;
6080 ASSERT(args.length() == 2);
6081
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006082 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6083 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006084 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006085}
6086
6087
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006088RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006089 NoHandleAllocation ha;
6090 ASSERT(args.length() == 2);
6091
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006092 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6093 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006094
ager@chromium.org3811b432009-10-28 14:53:37 +00006095 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006096 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006097 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006098}
6099
6100
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006101RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006102 NoHandleAllocation ha;
6103 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006104 CONVERT_CHECKED(String, str1, args[0]);
6105 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006106 isolate->counters()->string_add_runtime()->Increment();
6107 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006108}
6109
6110
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006111template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006112static inline void StringBuilderConcatHelper(String* special,
6113 sinkchar* sink,
6114 FixedArray* fixed_array,
6115 int array_length) {
6116 int position = 0;
6117 for (int i = 0; i < array_length; i++) {
6118 Object* element = fixed_array->get(i);
6119 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006120 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006121 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006122 int pos;
6123 int len;
6124 if (encoded_slice > 0) {
6125 // Position and length encoded in one smi.
6126 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6127 len = StringBuilderSubstringLength::decode(encoded_slice);
6128 } else {
6129 // Position and length encoded in two smis.
6130 Object* obj = fixed_array->get(++i);
6131 ASSERT(obj->IsSmi());
6132 pos = Smi::cast(obj)->value();
6133 len = -encoded_slice;
6134 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006135 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006136 sink + position,
6137 pos,
6138 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006139 position += len;
6140 } else {
6141 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006142 int element_length = string->length();
6143 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006144 position += element_length;
6145 }
6146 }
6147}
6148
6149
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006150RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006151 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006152 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006153 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006154 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006155 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006156 return Failure::OutOfMemoryException();
6157 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006158 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006159 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006160
6161 // This assumption is used by the slice encoding in one or two smis.
6162 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6163
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006164 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006165 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006166 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006167 }
6168 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006169 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006170 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006171 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006172
6173 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006174 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006175 } else if (array_length == 1) {
6176 Object* first = fixed_array->get(0);
6177 if (first->IsString()) return first;
6178 }
6179
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006180 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006181 int position = 0;
6182 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006183 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006184 Object* elt = fixed_array->get(i);
6185 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006186 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006187 int smi_value = Smi::cast(elt)->value();
6188 int pos;
6189 int len;
6190 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006191 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006192 pos = StringBuilderSubstringPosition::decode(smi_value);
6193 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006194 } else {
6195 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006196 len = -smi_value;
6197 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006198 i++;
6199 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006200 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006201 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006202 Object* next_smi = fixed_array->get(i);
6203 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006204 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006205 }
6206 pos = Smi::cast(next_smi)->value();
6207 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006208 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006209 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006210 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006211 ASSERT(pos >= 0);
6212 ASSERT(len >= 0);
6213 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006214 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006215 }
6216 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006217 } else if (elt->IsString()) {
6218 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006219 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006220 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006221 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006222 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006223 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006224 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006225 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006226 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006227 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006228 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006229 return Failure::OutOfMemoryException();
6230 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006231 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006232 }
6233
6234 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006235 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006236
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006237 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006238 { MaybeObject* maybe_object =
6239 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006240 if (!maybe_object->ToObject(&object)) return maybe_object;
6241 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006242 SeqAsciiString* answer = SeqAsciiString::cast(object);
6243 StringBuilderConcatHelper(special,
6244 answer->GetChars(),
6245 fixed_array,
6246 array_length);
6247 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006248 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006249 { MaybeObject* maybe_object =
6250 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006251 if (!maybe_object->ToObject(&object)) return maybe_object;
6252 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006253 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6254 StringBuilderConcatHelper(special,
6255 answer->GetChars(),
6256 fixed_array,
6257 array_length);
6258 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006259 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006260}
6261
6262
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006263RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006264 NoHandleAllocation ha;
6265 ASSERT(args.length() == 3);
6266 CONVERT_CHECKED(JSArray, array, args[0]);
6267 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006268 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006269 return Failure::OutOfMemoryException();
6270 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006271 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006272 CONVERT_CHECKED(String, separator, args[2]);
6273
6274 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006275 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006276 }
6277 FixedArray* fixed_array = FixedArray::cast(array->elements());
6278 if (fixed_array->length() < array_length) {
6279 array_length = fixed_array->length();
6280 }
6281
6282 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006283 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006284 } else if (array_length == 1) {
6285 Object* first = fixed_array->get(0);
6286 if (first->IsString()) return first;
6287 }
6288
6289 int separator_length = separator->length();
6290 int max_nof_separators =
6291 (String::kMaxLength + separator_length - 1) / separator_length;
6292 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006293 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006294 return Failure::OutOfMemoryException();
6295 }
6296 int length = (array_length - 1) * separator_length;
6297 for (int i = 0; i < array_length; i++) {
6298 Object* element_obj = fixed_array->get(i);
6299 if (!element_obj->IsString()) {
6300 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006301 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006302 }
6303 String* element = String::cast(element_obj);
6304 int increment = element->length();
6305 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006306 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006307 return Failure::OutOfMemoryException();
6308 }
6309 length += increment;
6310 }
6311
6312 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006313 { MaybeObject* maybe_object =
6314 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006315 if (!maybe_object->ToObject(&object)) return maybe_object;
6316 }
6317 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6318
6319 uc16* sink = answer->GetChars();
6320#ifdef DEBUG
6321 uc16* end = sink + length;
6322#endif
6323
6324 String* first = String::cast(fixed_array->get(0));
6325 int first_length = first->length();
6326 String::WriteToFlat(first, sink, 0, first_length);
6327 sink += first_length;
6328
6329 for (int i = 1; i < array_length; i++) {
6330 ASSERT(sink + separator_length <= end);
6331 String::WriteToFlat(separator, sink, 0, separator_length);
6332 sink += separator_length;
6333
6334 String* element = String::cast(fixed_array->get(i));
6335 int element_length = element->length();
6336 ASSERT(sink + element_length <= end);
6337 String::WriteToFlat(element, sink, 0, element_length);
6338 sink += element_length;
6339 }
6340 ASSERT(sink == end);
6341
6342 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6343 return answer;
6344}
6345
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006346template <typename Char>
6347static void JoinSparseArrayWithSeparator(FixedArray* elements,
6348 int elements_length,
6349 uint32_t array_length,
6350 String* separator,
6351 Vector<Char> buffer) {
6352 int previous_separator_position = 0;
6353 int separator_length = separator->length();
6354 int cursor = 0;
6355 for (int i = 0; i < elements_length; i += 2) {
6356 int position = NumberToInt32(elements->get(i));
6357 String* string = String::cast(elements->get(i + 1));
6358 int string_length = string->length();
6359 if (string->length() > 0) {
6360 while (previous_separator_position < position) {
6361 String::WriteToFlat<Char>(separator, &buffer[cursor],
6362 0, separator_length);
6363 cursor += separator_length;
6364 previous_separator_position++;
6365 }
6366 String::WriteToFlat<Char>(string, &buffer[cursor],
6367 0, string_length);
6368 cursor += string->length();
6369 }
6370 }
6371 if (separator_length > 0) {
6372 // Array length must be representable as a signed 32-bit number,
6373 // otherwise the total string length would have been too large.
6374 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6375 int last_array_index = static_cast<int>(array_length - 1);
6376 while (previous_separator_position < last_array_index) {
6377 String::WriteToFlat<Char>(separator, &buffer[cursor],
6378 0, separator_length);
6379 cursor += separator_length;
6380 previous_separator_position++;
6381 }
6382 }
6383 ASSERT(cursor <= buffer.length());
6384}
6385
6386
6387RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6388 NoHandleAllocation ha;
6389 ASSERT(args.length() == 3);
6390 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6391 RUNTIME_ASSERT(elements_array->HasFastElements());
6392 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6393 CONVERT_CHECKED(String, separator, args[2]);
6394 // elements_array is fast-mode JSarray of alternating positions
6395 // (increasing order) and strings.
6396 // array_length is length of original array (used to add separators);
6397 // separator is string to put between elements. Assumed to be non-empty.
6398
6399 // Find total length of join result.
6400 int string_length = 0;
6401 bool is_ascii = true;
6402 int max_string_length = SeqAsciiString::kMaxLength;
6403 bool overflow = false;
6404 CONVERT_NUMBER_CHECKED(int, elements_length,
6405 Int32, elements_array->length());
6406 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6407 FixedArray* elements = FixedArray::cast(elements_array->elements());
6408 for (int i = 0; i < elements_length; i += 2) {
6409 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6410 CONVERT_CHECKED(String, string, elements->get(i + 1));
6411 int length = string->length();
6412 if (is_ascii && !string->IsAsciiRepresentation()) {
6413 is_ascii = false;
6414 max_string_length = SeqTwoByteString::kMaxLength;
6415 }
6416 if (length > max_string_length ||
6417 max_string_length - length < string_length) {
6418 overflow = true;
6419 break;
6420 }
6421 string_length += length;
6422 }
6423 int separator_length = separator->length();
6424 if (!overflow && separator_length > 0) {
6425 if (array_length <= 0x7fffffffu) {
6426 int separator_count = static_cast<int>(array_length) - 1;
6427 int remaining_length = max_string_length - string_length;
6428 if ((remaining_length / separator_length) >= separator_count) {
6429 string_length += separator_length * (array_length - 1);
6430 } else {
6431 // Not room for the separators within the maximal string length.
6432 overflow = true;
6433 }
6434 } else {
6435 // Nonempty separator and at least 2^31-1 separators necessary
6436 // means that the string is too large to create.
6437 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6438 overflow = true;
6439 }
6440 }
6441 if (overflow) {
6442 // Throw OutOfMemory exception for creating too large a string.
6443 V8::FatalProcessOutOfMemory("Array join result too large.");
6444 }
6445
6446 if (is_ascii) {
6447 MaybeObject* result_allocation =
6448 isolate->heap()->AllocateRawAsciiString(string_length);
6449 if (result_allocation->IsFailure()) return result_allocation;
6450 SeqAsciiString* result_string =
6451 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6452 JoinSparseArrayWithSeparator<char>(elements,
6453 elements_length,
6454 array_length,
6455 separator,
6456 Vector<char>(result_string->GetChars(),
6457 string_length));
6458 return result_string;
6459 } else {
6460 MaybeObject* result_allocation =
6461 isolate->heap()->AllocateRawTwoByteString(string_length);
6462 if (result_allocation->IsFailure()) return result_allocation;
6463 SeqTwoByteString* result_string =
6464 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6465 JoinSparseArrayWithSeparator<uc16>(elements,
6466 elements_length,
6467 array_length,
6468 separator,
6469 Vector<uc16>(result_string->GetChars(),
6470 string_length));
6471 return result_string;
6472 }
6473}
6474
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006475
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006476RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006477 NoHandleAllocation ha;
6478 ASSERT(args.length() == 2);
6479
6480 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6481 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006482 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006483}
6484
6485
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006486RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006487 NoHandleAllocation ha;
6488 ASSERT(args.length() == 2);
6489
6490 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6491 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006492 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006493}
6494
6495
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006496RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006497 NoHandleAllocation ha;
6498 ASSERT(args.length() == 2);
6499
6500 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6501 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006502 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006503}
6504
6505
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006506RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006507 NoHandleAllocation ha;
6508 ASSERT(args.length() == 1);
6509
6510 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006511 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006512}
6513
6514
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006515RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006516 NoHandleAllocation ha;
6517 ASSERT(args.length() == 2);
6518
6519 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6520 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006521 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006522}
6523
6524
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006525RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006526 NoHandleAllocation ha;
6527 ASSERT(args.length() == 2);
6528
6529 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6530 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006531 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006532}
6533
6534
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006535RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006536 NoHandleAllocation ha;
6537 ASSERT(args.length() == 2);
6538
6539 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6540 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006541 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006542}
6543
6544
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006545RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006546 NoHandleAllocation ha;
6547 ASSERT(args.length() == 2);
6548
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006549 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6550 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006551 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6552 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6553 if (x == y) return Smi::FromInt(EQUAL);
6554 Object* result;
6555 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6556 result = Smi::FromInt(EQUAL);
6557 } else {
6558 result = Smi::FromInt(NOT_EQUAL);
6559 }
6560 return result;
6561}
6562
6563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006564RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006565 NoHandleAllocation ha;
6566 ASSERT(args.length() == 2);
6567
6568 CONVERT_CHECKED(String, x, args[0]);
6569 CONVERT_CHECKED(String, y, args[1]);
6570
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006571 bool not_equal = !x->Equals(y);
6572 // This is slightly convoluted because the value that signifies
6573 // equality is 0 and inequality is 1 so we have to negate the result
6574 // from String::Equals.
6575 ASSERT(not_equal == 0 || not_equal == 1);
6576 STATIC_CHECK(EQUAL == 0);
6577 STATIC_CHECK(NOT_EQUAL == 1);
6578 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006579}
6580
6581
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006582RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006583 NoHandleAllocation ha;
6584 ASSERT(args.length() == 3);
6585
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006586 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6587 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006588 if (isnan(x) || isnan(y)) return args[2];
6589 if (x == y) return Smi::FromInt(EQUAL);
6590 if (isless(x, y)) return Smi::FromInt(LESS);
6591 return Smi::FromInt(GREATER);
6592}
6593
6594
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006595// Compare two Smis as if they were converted to strings and then
6596// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006597RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006598 NoHandleAllocation ha;
6599 ASSERT(args.length() == 2);
6600
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006601 // Extract the integer values from the Smis.
6602 CONVERT_CHECKED(Smi, x, args[0]);
6603 CONVERT_CHECKED(Smi, y, args[1]);
6604 int x_value = x->value();
6605 int y_value = y->value();
6606
6607 // If the integers are equal so are the string representations.
6608 if (x_value == y_value) return Smi::FromInt(EQUAL);
6609
6610 // If one of the integers are zero the normal integer order is the
6611 // same as the lexicographic order of the string representations.
6612 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6613
ager@chromium.org32912102009-01-16 10:38:43 +00006614 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006615 // smallest because the char code of '-' is less than the char code
6616 // of any digit. Otherwise, we make both values positive.
6617 if (x_value < 0 || y_value < 0) {
6618 if (y_value >= 0) return Smi::FromInt(LESS);
6619 if (x_value >= 0) return Smi::FromInt(GREATER);
6620 x_value = -x_value;
6621 y_value = -y_value;
6622 }
6623
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006624 // Arrays for the individual characters of the two Smis. Smis are
6625 // 31 bit integers and 10 decimal digits are therefore enough.
6626 // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
6627 int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
6628 int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
6629
6630
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006631 // Convert the integers to arrays of their decimal digits.
6632 int x_index = 0;
6633 int y_index = 0;
6634 while (x_value > 0) {
6635 x_elms[x_index++] = x_value % 10;
6636 x_value /= 10;
6637 }
6638 while (y_value > 0) {
6639 y_elms[y_index++] = y_value % 10;
6640 y_value /= 10;
6641 }
6642
6643 // Loop through the arrays of decimal digits finding the first place
6644 // where they differ.
6645 while (--x_index >= 0 && --y_index >= 0) {
6646 int diff = x_elms[x_index] - y_elms[y_index];
6647 if (diff != 0) return Smi::FromInt(diff);
6648 }
6649
6650 // If one array is a suffix of the other array, the longest array is
6651 // the representation of the largest of the Smis in the
6652 // lexicographic ordering.
6653 return Smi::FromInt(x_index - y_index);
6654}
6655
6656
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006657static Object* StringInputBufferCompare(RuntimeState* state,
6658 String* x,
6659 String* y) {
6660 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6661 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006662 bufx.Reset(x);
6663 bufy.Reset(y);
6664 while (bufx.has_more() && bufy.has_more()) {
6665 int d = bufx.GetNext() - bufy.GetNext();
6666 if (d < 0) return Smi::FromInt(LESS);
6667 else if (d > 0) return Smi::FromInt(GREATER);
6668 }
6669
6670 // x is (non-trivial) prefix of y:
6671 if (bufy.has_more()) return Smi::FromInt(LESS);
6672 // y is prefix of x:
6673 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6674}
6675
6676
6677static Object* FlatStringCompare(String* x, String* y) {
6678 ASSERT(x->IsFlat());
6679 ASSERT(y->IsFlat());
6680 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6681 int prefix_length = x->length();
6682 if (y->length() < prefix_length) {
6683 prefix_length = y->length();
6684 equal_prefix_result = Smi::FromInt(GREATER);
6685 } else if (y->length() > prefix_length) {
6686 equal_prefix_result = Smi::FromInt(LESS);
6687 }
6688 int r;
6689 if (x->IsAsciiRepresentation()) {
6690 Vector<const char> x_chars = x->ToAsciiVector();
6691 if (y->IsAsciiRepresentation()) {
6692 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006693 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006694 } else {
6695 Vector<const uc16> y_chars = y->ToUC16Vector();
6696 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6697 }
6698 } else {
6699 Vector<const uc16> x_chars = x->ToUC16Vector();
6700 if (y->IsAsciiRepresentation()) {
6701 Vector<const char> y_chars = y->ToAsciiVector();
6702 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6703 } else {
6704 Vector<const uc16> y_chars = y->ToUC16Vector();
6705 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6706 }
6707 }
6708 Object* result;
6709 if (r == 0) {
6710 result = equal_prefix_result;
6711 } else {
6712 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6713 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006714 ASSERT(result ==
6715 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006716 return result;
6717}
6718
6719
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006720RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006721 NoHandleAllocation ha;
6722 ASSERT(args.length() == 2);
6723
6724 CONVERT_CHECKED(String, x, args[0]);
6725 CONVERT_CHECKED(String, y, args[1]);
6726
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006727 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006728
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006729 // A few fast case tests before we flatten.
6730 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006731 if (y->length() == 0) {
6732 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006733 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006734 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006735 return Smi::FromInt(LESS);
6736 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006737
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006738 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006739 if (d < 0) return Smi::FromInt(LESS);
6740 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006741
lrn@chromium.org303ada72010-10-27 09:33:13 +00006742 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006743 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006744 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6745 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006746 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006747 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6748 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006749
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006750 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006751 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006752}
6753
6754
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006755RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006756 NoHandleAllocation ha;
6757 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006758 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006759
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006760 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006761 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006762}
6763
6764
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006765RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006766 NoHandleAllocation ha;
6767 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006768 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006769
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006770 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006771 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006772}
6773
6774
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006775RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006776 NoHandleAllocation ha;
6777 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006778 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006779
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006780 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006781 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006782}
6783
6784
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006785static const double kPiDividedBy4 = 0.78539816339744830962;
6786
6787
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006788RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006789 NoHandleAllocation ha;
6790 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006791 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006792
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006793 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6794 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006795 double result;
6796 if (isinf(x) && isinf(y)) {
6797 // Make sure that the result in case of two infinite arguments
6798 // is a multiple of Pi / 4. The sign of the result is determined
6799 // by the first argument (x) and the sign of the second argument
6800 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006801 int multiplier = (x < 0) ? -1 : 1;
6802 if (y < 0) multiplier *= 3;
6803 result = multiplier * kPiDividedBy4;
6804 } else {
6805 result = atan2(x, y);
6806 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006807 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006808}
6809
6810
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006811RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006812 NoHandleAllocation ha;
6813 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006814 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006815
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006816 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006817 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006818}
6819
6820
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006821RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006822 NoHandleAllocation ha;
6823 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006824 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006825
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006826 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006827 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006828}
6829
6830
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006831RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006832 NoHandleAllocation ha;
6833 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006834 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006835
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006836 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006837 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006838}
6839
6840
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006841RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006842 NoHandleAllocation ha;
6843 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006844 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006845
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006846 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006847 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006848}
6849
6850
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006851RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006852 NoHandleAllocation ha;
6853 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006854 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006855
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006856 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006857 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006858}
6859
6860
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006861RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006862 NoHandleAllocation ha;
6863 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006864 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006865
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006866 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006867
6868 // If the second argument is a smi, it is much faster to call the
6869 // custom powi() function than the generic pow().
6870 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006871 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006872 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006873 }
6874
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006875 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006876 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006877}
6878
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006879// Fast version of Math.pow if we know that y is not an integer and
6880// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006881RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006882 NoHandleAllocation ha;
6883 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006884 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6885 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006886 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006887 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006888 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006889 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006890 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006891 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006892 }
6893}
6894
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006895
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006896RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006897 NoHandleAllocation ha;
6898 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006899 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006900
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006901 if (!args[0]->IsHeapNumber()) {
6902 // Must be smi. Return the argument unchanged for all the other types
6903 // to make fuzz-natives test happy.
6904 return args[0];
6905 }
6906
6907 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6908
6909 double value = number->value();
6910 int exponent = number->get_exponent();
6911 int sign = number->get_sign();
6912
danno@chromium.org160a7b02011-04-18 15:51:38 +00006913 if (exponent < -1) {
6914 // Number in range ]-0.5..0.5[. These always round to +/-zero.
6915 if (sign) return isolate->heap()->minus_zero_value();
6916 return Smi::FromInt(0);
6917 }
6918
6919 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
6920 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
6921 // agument holds for 32-bit smis).
6922 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006923 return Smi::FromInt(static_cast<int>(value + 0.5));
6924 }
6925
6926 // If the magnitude is big enough, there's no place for fraction part. If we
6927 // try to add 0.5 to this number, 1.0 will be added instead.
6928 if (exponent >= 52) {
6929 return number;
6930 }
6931
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006932 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006933
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006934 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006935 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006936}
6937
6938
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006939RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006940 NoHandleAllocation ha;
6941 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006942 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006943
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006944 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006945 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006946}
6947
6948
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006949RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006950 NoHandleAllocation ha;
6951 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006952 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006953
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006954 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006955 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006956}
6957
6958
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006959RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006960 NoHandleAllocation ha;
6961 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006962 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006963
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006964 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006965 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006966}
6967
6968
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006969static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006970 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6971 181, 212, 243, 273, 304, 334};
6972 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6973 182, 213, 244, 274, 305, 335};
6974
6975 year += month / 12;
6976 month %= 12;
6977 if (month < 0) {
6978 year--;
6979 month += 12;
6980 }
6981
6982 ASSERT(month >= 0);
6983 ASSERT(month < 12);
6984
6985 // year_delta is an arbitrary number such that:
6986 // a) year_delta = -1 (mod 400)
6987 // b) year + year_delta > 0 for years in the range defined by
6988 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6989 // Jan 1 1970. This is required so that we don't run into integer
6990 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006991 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006992 // operations.
6993 static const int year_delta = 399999;
6994 static const int base_day = 365 * (1970 + year_delta) +
6995 (1970 + year_delta) / 4 -
6996 (1970 + year_delta) / 100 +
6997 (1970 + year_delta) / 400;
6998
6999 int year1 = year + year_delta;
7000 int day_from_year = 365 * year1 +
7001 year1 / 4 -
7002 year1 / 100 +
7003 year1 / 400 -
7004 base_day;
7005
7006 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007007 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007008 }
7009
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007010 return day_from_year + day_from_month_leap[month] + day - 1;
7011}
7012
7013
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007014RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007015 NoHandleAllocation ha;
7016 ASSERT(args.length() == 3);
7017
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007018 CONVERT_SMI_ARG_CHECKED(year, 0);
7019 CONVERT_SMI_ARG_CHECKED(month, 1);
7020 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007021
7022 return Smi::FromInt(MakeDay(year, month, date));
7023}
7024
7025
7026static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7027static const int kDaysIn4Years = 4 * 365 + 1;
7028static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7029static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7030static const int kDays1970to2000 = 30 * 365 + 7;
7031static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7032 kDays1970to2000;
7033static const int kYearsOffset = 400000;
7034
7035static const char kDayInYear[] = {
7036 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7037 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7038 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7039 22, 23, 24, 25, 26, 27, 28,
7040 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7041 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7042 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7043 22, 23, 24, 25, 26, 27, 28, 29, 30,
7044 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7045 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7046 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7047 22, 23, 24, 25, 26, 27, 28, 29, 30,
7048 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7049 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7050 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7051 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7052 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7053 22, 23, 24, 25, 26, 27, 28, 29, 30,
7054 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7055 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7056 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7057 22, 23, 24, 25, 26, 27, 28, 29, 30,
7058 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7059 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7060
7061 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7062 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7063 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7064 22, 23, 24, 25, 26, 27, 28,
7065 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7066 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7067 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7068 22, 23, 24, 25, 26, 27, 28, 29, 30,
7069 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7070 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7071 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7072 22, 23, 24, 25, 26, 27, 28, 29, 30,
7073 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7074 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7075 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7076 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7077 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7078 22, 23, 24, 25, 26, 27, 28, 29, 30,
7079 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7080 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7081 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7082 22, 23, 24, 25, 26, 27, 28, 29, 30,
7083 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7084 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7085
7086 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7087 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7088 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7089 22, 23, 24, 25, 26, 27, 28, 29,
7090 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7091 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7092 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7093 22, 23, 24, 25, 26, 27, 28, 29, 30,
7094 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7095 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7096 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7097 22, 23, 24, 25, 26, 27, 28, 29, 30,
7098 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7099 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7100 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7101 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7102 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7103 22, 23, 24, 25, 26, 27, 28, 29, 30,
7104 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7105 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7106 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7107 22, 23, 24, 25, 26, 27, 28, 29, 30,
7108 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7109 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7110
7111 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7112 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7113 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7114 22, 23, 24, 25, 26, 27, 28,
7115 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7116 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7117 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7118 22, 23, 24, 25, 26, 27, 28, 29, 30,
7119 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7120 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7121 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7122 22, 23, 24, 25, 26, 27, 28, 29, 30,
7123 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7124 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7125 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7126 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7127 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7128 22, 23, 24, 25, 26, 27, 28, 29, 30,
7129 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7130 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7131 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7132 22, 23, 24, 25, 26, 27, 28, 29, 30,
7133 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7134 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7135
7136static const char kMonthInYear[] = {
7137 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,
7138 0, 0, 0, 0, 0, 0,
7139 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,
7140 1, 1, 1,
7141 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,
7142 2, 2, 2, 2, 2, 2,
7143 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,
7144 3, 3, 3, 3, 3,
7145 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,
7146 4, 4, 4, 4, 4, 4,
7147 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,
7148 5, 5, 5, 5, 5,
7149 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,
7150 6, 6, 6, 6, 6, 6,
7151 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,
7152 7, 7, 7, 7, 7, 7,
7153 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,
7154 8, 8, 8, 8, 8,
7155 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,
7156 9, 9, 9, 9, 9, 9,
7157 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7158 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7159 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7160 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7161
7162 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,
7163 0, 0, 0, 0, 0, 0,
7164 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,
7165 1, 1, 1,
7166 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,
7167 2, 2, 2, 2, 2, 2,
7168 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,
7169 3, 3, 3, 3, 3,
7170 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,
7171 4, 4, 4, 4, 4, 4,
7172 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,
7173 5, 5, 5, 5, 5,
7174 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,
7175 6, 6, 6, 6, 6, 6,
7176 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,
7177 7, 7, 7, 7, 7, 7,
7178 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,
7179 8, 8, 8, 8, 8,
7180 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,
7181 9, 9, 9, 9, 9, 9,
7182 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7183 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7184 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7185 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7186
7187 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,
7188 0, 0, 0, 0, 0, 0,
7189 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,
7190 1, 1, 1, 1,
7191 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,
7192 2, 2, 2, 2, 2, 2,
7193 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,
7194 3, 3, 3, 3, 3,
7195 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,
7196 4, 4, 4, 4, 4, 4,
7197 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,
7198 5, 5, 5, 5, 5,
7199 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,
7200 6, 6, 6, 6, 6, 6,
7201 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,
7202 7, 7, 7, 7, 7, 7,
7203 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,
7204 8, 8, 8, 8, 8,
7205 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,
7206 9, 9, 9, 9, 9, 9,
7207 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7208 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7209 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7210 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7211
7212 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,
7213 0, 0, 0, 0, 0, 0,
7214 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,
7215 1, 1, 1,
7216 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,
7217 2, 2, 2, 2, 2, 2,
7218 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,
7219 3, 3, 3, 3, 3,
7220 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,
7221 4, 4, 4, 4, 4, 4,
7222 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,
7223 5, 5, 5, 5, 5,
7224 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,
7225 6, 6, 6, 6, 6, 6,
7226 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,
7227 7, 7, 7, 7, 7, 7,
7228 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,
7229 8, 8, 8, 8, 8,
7230 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,
7231 9, 9, 9, 9, 9, 9,
7232 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7233 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7234 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7235 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7236
7237
7238// This function works for dates from 1970 to 2099.
7239static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007240 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007241#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007242 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007243#endif
7244
7245 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7246 date %= kDaysIn4Years;
7247
7248 month = kMonthInYear[date];
7249 day = kDayInYear[date];
7250
7251 ASSERT(MakeDay(year, month, day) == save_date);
7252}
7253
7254
7255static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007256 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007257#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007258 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007259#endif
7260
7261 date += kDaysOffset;
7262 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7263 date %= kDaysIn400Years;
7264
7265 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7266
7267 date--;
7268 int yd1 = date / kDaysIn100Years;
7269 date %= kDaysIn100Years;
7270 year += 100 * yd1;
7271
7272 date++;
7273 int yd2 = date / kDaysIn4Years;
7274 date %= kDaysIn4Years;
7275 year += 4 * yd2;
7276
7277 date--;
7278 int yd3 = date / 365;
7279 date %= 365;
7280 year += yd3;
7281
7282 bool is_leap = (!yd1 || yd2) && !yd3;
7283
7284 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007285 ASSERT(is_leap || (date >= 0));
7286 ASSERT((date < 365) || (is_leap && (date < 366)));
7287 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7288 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7289 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007290
7291 if (is_leap) {
7292 day = kDayInYear[2*365 + 1 + date];
7293 month = kMonthInYear[2*365 + 1 + date];
7294 } else {
7295 day = kDayInYear[date];
7296 month = kMonthInYear[date];
7297 }
7298
7299 ASSERT(MakeDay(year, month, day) == save_date);
7300}
7301
7302
7303static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007304 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007305 if (date >= 0 && date < 32 * kDaysIn4Years) {
7306 DateYMDFromTimeAfter1970(date, year, month, day);
7307 } else {
7308 DateYMDFromTimeSlow(date, year, month, day);
7309 }
7310}
7311
7312
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007313RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007314 NoHandleAllocation ha;
7315 ASSERT(args.length() == 2);
7316
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007317 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007318 CONVERT_CHECKED(JSArray, res_array, args[1]);
7319
7320 int year, month, day;
7321 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7322
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007323 RUNTIME_ASSERT(res_array->elements()->map() ==
7324 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007325 FixedArray* elms = FixedArray::cast(res_array->elements());
7326 RUNTIME_ASSERT(elms->length() == 3);
7327
7328 elms->set(0, Smi::FromInt(year));
7329 elms->set(1, Smi::FromInt(month));
7330 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007331
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007332 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007333}
7334
7335
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007336RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007337 NoHandleAllocation ha;
7338 ASSERT(args.length() == 3);
7339
7340 JSFunction* callee = JSFunction::cast(args[0]);
7341 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007342 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007343
lrn@chromium.org303ada72010-10-27 09:33:13 +00007344 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007345 { MaybeObject* maybe_result =
7346 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007347 if (!maybe_result->ToObject(&result)) return maybe_result;
7348 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007349 // Allocate the elements if needed.
7350 if (length > 0) {
7351 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007352 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007353 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007354 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7355 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007356
7357 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007358 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007359 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007360 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007361
7362 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007363 for (int i = 0; i < length; i++) {
7364 array->set(i, *--parameters, mode);
7365 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007366 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007367 }
7368 return result;
7369}
7370
7371
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007372RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007373 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007374 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007375 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007376 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007377 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007378
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007379 // Allocate global closures in old space and allocate local closures
7380 // in new space. Additionally pretenure closures that are assigned
7381 // directly to properties.
7382 pretenure = pretenure || (context->global_context() == *context);
7383 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007384 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007385 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7386 context,
7387 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007388 return *result;
7389}
7390
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007391
7392static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7393 int* total_argc) {
7394 // Find frame containing arguments passed to the caller.
7395 JavaScriptFrameIterator it;
7396 JavaScriptFrame* frame = it.frame();
7397 List<JSFunction*> functions(2);
7398 frame->GetFunctions(&functions);
7399 if (functions.length() > 1) {
7400 int inlined_frame_index = functions.length() - 1;
7401 JSFunction* inlined_function = functions[inlined_frame_index];
7402 int args_count = inlined_function->shared()->formal_parameter_count();
7403 ScopedVector<SlotRef> args_slots(args_count);
7404 SlotRef::ComputeSlotMappingForArguments(frame,
7405 inlined_frame_index,
7406 &args_slots);
7407
7408 *total_argc = bound_argc + args_count;
7409 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7410 for (int i = 0; i < args_count; i++) {
7411 Handle<Object> val = args_slots[i].GetValue();
7412 param_data[bound_argc + i] = val.location();
7413 }
7414 return param_data;
7415 } else {
7416 it.AdvanceToArgumentsFrame();
7417 frame = it.frame();
7418 int args_count = frame->ComputeParametersCount();
7419
7420 *total_argc = bound_argc + args_count;
7421 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7422 for (int i = 0; i < args_count; i++) {
7423 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7424 param_data[bound_argc + i] = val.location();
7425 }
7426 return param_data;
7427 }
7428}
7429
7430
7431RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007432 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007433 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007434 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007435 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007436
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007437 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007438 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007439 int bound_argc = 0;
7440 if (!args[1]->IsNull()) {
7441 CONVERT_ARG_CHECKED(JSArray, params, 1);
7442 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007443 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007444 bound_argc = Smi::cast(params->length())->value();
7445 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007446
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007447 int total_argc = 0;
7448 SmartPointer<Object**> param_data =
7449 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007450 for (int i = 0; i < bound_argc; i++) {
7451 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007452 param_data[i] = val.location();
7453 }
7454
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007455 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007456 Handle<Object> result =
7457 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007458 if (exception) {
7459 return Failure::Exception();
7460 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007461
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007462 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007463 return *result;
7464}
7465
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007466
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007467static void TrySettingInlineConstructStub(Isolate* isolate,
7468 Handle<JSFunction> function) {
7469 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007470 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007471 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007472 }
7473 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007474 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007475 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007476 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007477 function->shared()->set_construct_stub(
7478 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007479 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007480 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007481}
7482
7483
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007484RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007485 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007486 ASSERT(args.length() == 1);
7487
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007488 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007489
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007490 // If the constructor isn't a proper function we throw a type error.
7491 if (!constructor->IsJSFunction()) {
7492 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7493 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007494 isolate->factory()->NewTypeError("not_constructor", arguments);
7495 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007496 }
7497
7498 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007499
7500 // If function should not have prototype, construction is not allowed. In this
7501 // case generated code bailouts here, since function has no initial_map.
7502 if (!function->should_have_prototype()) {
7503 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7504 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007505 isolate->factory()->NewTypeError("not_constructor", arguments);
7506 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007507 }
7508
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007509#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007510 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007511 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007512 if (debug->StepInActive()) {
7513 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007514 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007515#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007516
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007517 if (function->has_initial_map()) {
7518 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007519 // The 'Function' function ignores the receiver object when
7520 // called using 'new' and creates a new JSFunction object that
7521 // is returned. The receiver object is only used for error
7522 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007523 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007524 // allocate JSFunctions since it does not properly initialize
7525 // the shared part of the function. Since the receiver is
7526 // ignored anyway, we use the global object as the receiver
7527 // instead of a new JSFunction object. This way, errors are
7528 // reported the same way whether or not 'Function' is called
7529 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007530 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007531 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007532 }
7533
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007534 // The function should be compiled for the optimization hints to be
7535 // available. We cannot use EnsureCompiled because that forces a
7536 // compilation through the shared function info which makes it
7537 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007538 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007539 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007540
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007541 if (!function->has_initial_map() &&
7542 shared->IsInobjectSlackTrackingInProgress()) {
7543 // The tracking is already in progress for another function. We can only
7544 // track one initial_map at a time, so we force the completion before the
7545 // function is called as a constructor for the first time.
7546 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007547 }
7548
7549 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007550 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7551 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007552 // Delay setting the stub if inobject slack tracking is in progress.
7553 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007554 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007555 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007556
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007557 isolate->counters()->constructed_objects()->Increment();
7558 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007559
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007560 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007561}
7562
7563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007564RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007565 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007566 ASSERT(args.length() == 1);
7567
7568 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7569 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007570 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007571
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007572 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007573}
7574
7575
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007576RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007577 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007578 ASSERT(args.length() == 1);
7579
7580 Handle<JSFunction> function = args.at<JSFunction>(0);
7581#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007582 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007583 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007584 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007585 PrintF("]\n");
7586 }
7587#endif
7588
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007589 // Compile the target function. Here we compile using CompileLazyInLoop in
7590 // order to get the optimized version. This helps code like delta-blue
7591 // that calls performance-critical routines through constructors. A
7592 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7593 // direct call. Since the in-loop tracking takes place through CallICs
7594 // this means that things called through constructors are never known to
7595 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007596 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007597 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007598 return Failure::Exception();
7599 }
7600
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007601 // All done. Return the compiled code.
7602 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007603 return function->code();
7604}
7605
7606
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007607RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007608 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007609 ASSERT(args.length() == 1);
7610 Handle<JSFunction> function = args.at<JSFunction>(0);
7611 // If the function is not optimizable or debugger is active continue using the
7612 // code from the full compiler.
7613 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007614 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007615 if (FLAG_trace_opt) {
7616 PrintF("[failed to optimize ");
7617 function->PrintName();
7618 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7619 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007620 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007621 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007622 function->ReplaceCode(function->shared()->code());
7623 return function->code();
7624 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007625 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007626 return function->code();
7627 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007628 if (FLAG_trace_opt) {
7629 PrintF("[failed to optimize ");
7630 function->PrintName();
7631 PrintF(": optimized compilation failed]\n");
7632 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007633 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007634 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007635}
7636
7637
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007638RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007639 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007640 ASSERT(args.length() == 1);
7641 RUNTIME_ASSERT(args[0]->IsSmi());
7642 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007643 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007644 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7645 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007646 int frames = deoptimizer->output_count();
7647
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007648 deoptimizer->MaterializeHeapNumbers();
7649 delete deoptimizer;
7650
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007651 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007652 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007653 for (int i = 0; i < frames - 1; i++) it.Advance();
7654 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007655
7656 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007657 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007658 Handle<Object> arguments;
7659 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007660 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007661 if (arguments.is_null()) {
7662 // FunctionGetArguments can't throw an exception, so cast away the
7663 // doubt with an assert.
7664 arguments = Handle<Object>(
7665 Accessors::FunctionGetArguments(*function,
7666 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007667 ASSERT(*arguments != isolate->heap()->null_value());
7668 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007669 }
7670 frame->SetExpression(i, *arguments);
7671 }
7672 }
7673
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007674 isolate->compilation_cache()->MarkForLazyOptimizing(function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007675 if (type == Deoptimizer::EAGER) {
7676 RUNTIME_ASSERT(function->IsOptimized());
7677 } else {
7678 RUNTIME_ASSERT(!function->IsOptimized());
7679 }
7680
7681 // Avoid doing too much work when running with --always-opt and keep
7682 // the optimized code around.
7683 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007684 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007685 }
7686
7687 // Count the number of optimized activations of the function.
7688 int activations = 0;
7689 while (!it.done()) {
7690 JavaScriptFrame* frame = it.frame();
7691 if (frame->is_optimized() && frame->function() == *function) {
7692 activations++;
7693 }
7694 it.Advance();
7695 }
7696
7697 // TODO(kasperl): For now, we cannot support removing the optimized
7698 // code when we have recursive invocations of the same function.
7699 if (activations == 0) {
7700 if (FLAG_trace_deopt) {
7701 PrintF("[removing optimized code for: ");
7702 function->PrintName();
7703 PrintF("]\n");
7704 }
7705 function->ReplaceCode(function->shared()->code());
7706 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007707 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007708}
7709
7710
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007711RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007712 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007713 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007714 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007715}
7716
7717
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007718RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007719 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007720 ASSERT(args.length() == 1);
7721 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007722 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007723
7724 Deoptimizer::DeoptimizeFunction(*function);
7725
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007726 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007727}
7728
7729
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007730RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
7731#if defined(USE_SIMULATOR)
7732 return isolate->heap()->true_value();
7733#else
7734 return isolate->heap()->false_value();
7735#endif
7736}
7737
7738
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007739RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7740 HandleScope scope(isolate);
7741 ASSERT(args.length() == 1);
7742 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7743 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7744 function->MarkForLazyRecompilation();
7745 return isolate->heap()->undefined_value();
7746}
7747
7748
lrn@chromium.org1c092762011-05-09 09:42:16 +00007749RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
7750 HandleScope scope(isolate);
7751 ASSERT(args.length() == 1);
7752 if (!V8::UseCrankshaft()) {
7753 return Smi::FromInt(4); // 4 == "never".
7754 }
7755 if (FLAG_always_opt) {
7756 return Smi::FromInt(3); // 3 == "always".
7757 }
7758 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7759 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
7760 : Smi::FromInt(2); // 2 == "no".
7761}
7762
7763
7764RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
7765 HandleScope scope(isolate);
7766 ASSERT(args.length() == 1);
7767 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7768 return Smi::FromInt(function->shared()->opt_count());
7769}
7770
7771
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007772RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007773 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007774 ASSERT(args.length() == 1);
7775 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7776
7777 // We're not prepared to handle a function with arguments object.
7778 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7779
7780 // We have hit a back edge in an unoptimized frame for a function that was
7781 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007782 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007783 // Keep track of whether we've succeeded in optimizing.
7784 bool succeeded = unoptimized->optimizable();
7785 if (succeeded) {
7786 // If we are trying to do OSR when there are already optimized
7787 // activations of the function, it means (a) the function is directly or
7788 // indirectly recursive and (b) an optimized invocation has been
7789 // deoptimized so that we are currently in an unoptimized activation.
7790 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007791 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007792 while (succeeded && !it.done()) {
7793 JavaScriptFrame* frame = it.frame();
7794 succeeded = !frame->is_optimized() || frame->function() != *function;
7795 it.Advance();
7796 }
7797 }
7798
7799 int ast_id = AstNode::kNoNumber;
7800 if (succeeded) {
7801 // The top JS function is this one, the PC is somewhere in the
7802 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007803 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007804 JavaScriptFrame* frame = it.frame();
7805 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007806 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007807 ASSERT(unoptimized->contains(frame->pc()));
7808
7809 // Use linear search of the unoptimized code's stack check table to find
7810 // the AST id matching the PC.
7811 Address start = unoptimized->instruction_start();
7812 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007813 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007814 uint32_t table_length = Memory::uint32_at(table_cursor);
7815 table_cursor += kIntSize;
7816 for (unsigned i = 0; i < table_length; ++i) {
7817 // Table entries are (AST id, pc offset) pairs.
7818 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7819 if (pc_offset == target_pc_offset) {
7820 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7821 break;
7822 }
7823 table_cursor += 2 * kIntSize;
7824 }
7825 ASSERT(ast_id != AstNode::kNoNumber);
7826 if (FLAG_trace_osr) {
7827 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7828 function->PrintName();
7829 PrintF("]\n");
7830 }
7831
7832 // Try to compile the optimized code. A true return value from
7833 // CompileOptimized means that compilation succeeded, not necessarily
7834 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007835 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7836 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007837 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7838 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007839 if (data->OsrPcOffset()->value() >= 0) {
7840 if (FLAG_trace_osr) {
7841 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007842 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007843 }
7844 ASSERT(data->OsrAstId()->value() == ast_id);
7845 } else {
7846 // We may never generate the desired OSR entry if we emit an
7847 // early deoptimize.
7848 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007849 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007850 } else {
7851 succeeded = false;
7852 }
7853 }
7854
7855 // Revert to the original stack checks in the original unoptimized code.
7856 if (FLAG_trace_osr) {
7857 PrintF("[restoring original stack checks in ");
7858 function->PrintName();
7859 PrintF("]\n");
7860 }
7861 StackCheckStub check_stub;
7862 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007863 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007864 Deoptimizer::RevertStackCheckCode(*unoptimized,
7865 *check_code,
7866 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007867
7868 // Allow OSR only at nesting level zero again.
7869 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7870
7871 // If the optimization attempt succeeded, return the AST id tagged as a
7872 // smi. This tells the builtin that we need to translate the unoptimized
7873 // frame to an optimized one.
7874 if (succeeded) {
7875 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7876 return Smi::FromInt(ast_id);
7877 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007878 if (function->IsMarkedForLazyRecompilation()) {
7879 function->ReplaceCode(function->shared()->code());
7880 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007881 return Smi::FromInt(-1);
7882 }
7883}
7884
7885
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007886RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007887 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007888 ASSERT(args.length() == 1);
7889 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7890 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7891}
7892
7893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007894RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007895 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007896 ASSERT(args.length() == 1);
7897 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7898 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7899}
7900
7901
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007902RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007903 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007904 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007905
kasper.lund7276f142008-07-30 08:49:36 +00007906 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007907 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007908 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007909 { MaybeObject* maybe_result =
7910 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007911 if (!maybe_result->ToObject(&result)) return maybe_result;
7912 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007913
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007914 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007915
kasper.lund7276f142008-07-30 08:49:36 +00007916 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007917}
7918
lrn@chromium.org303ada72010-10-27 09:33:13 +00007919
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007920RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
7921 NoHandleAllocation ha;
7922 ASSERT(args.length() == 1);
7923 JSObject* extension_object;
7924 if (args[0]->IsJSObject()) {
7925 extension_object = JSObject::cast(args[0]);
7926 } else {
7927 // Convert the object to a proper JavaScript object.
7928 MaybeObject* maybe_js_object = args[0]->ToObject();
7929 if (!maybe_js_object->To(&extension_object)) {
7930 if (Failure::cast(maybe_js_object)->IsInternalError()) {
7931 HandleScope scope(isolate);
7932 Handle<Object> handle = args.at<Object>(0);
7933 Handle<Object> result =
7934 isolate->factory()->NewTypeError("with_expression",
7935 HandleVector(&handle, 1));
7936 return isolate->Throw(*result);
7937 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007938 return maybe_js_object;
7939 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007940 }
7941 }
7942
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007943 Context* context;
7944 MaybeObject* maybe_context =
7945 isolate->heap()->AllocateWithContext(isolate->context(),
7946 extension_object);
7947 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007948 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007949 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007950}
7951
7952
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007953RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007954 NoHandleAllocation ha;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007955 ASSERT(args.length() == 2);
7956 String* name = String::cast(args[0]);
7957 Object* thrown_object = args[1];
7958 Context* context;
7959 MaybeObject* maybe_context =
7960 isolate->heap()->AllocateCatchContext(isolate->context(),
7961 name,
7962 thrown_object);
7963 if (!maybe_context->To(&context)) return maybe_context;
7964 isolate->set_context(context);
7965 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007966}
7967
7968
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007969RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007970 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007971 ASSERT(args.length() == 2);
7972
7973 CONVERT_ARG_CHECKED(Context, context, 0);
7974 CONVERT_ARG_CHECKED(String, name, 1);
7975
7976 int index;
7977 PropertyAttributes attributes;
7978 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007979 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007980
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007981 // If the slot was not found the result is true.
7982 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007983 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007984 }
7985
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007986 // If the slot was found in a context, it should be DONT_DELETE.
7987 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007988 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007989 }
7990
7991 // The slot was found in a JSObject, either a context extension object,
7992 // the global object, or an arguments object. Try to delete it
7993 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7994 // which allows deleting all parameters in functions that mention
7995 // 'arguments', we do this even for the case of slots found on an
7996 // arguments object. The slot was found on an arguments object if the
7997 // index is non-negative.
7998 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7999 if (index >= 0) {
8000 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
8001 } else {
8002 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
8003 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008004}
8005
8006
ager@chromium.orga1645e22009-09-09 19:27:10 +00008007// A mechanism to return a pair of Object pointers in registers (if possible).
8008// How this is achieved is calling convention-dependent.
8009// All currently supported x86 compiles uses calling conventions that are cdecl
8010// variants where a 64-bit value is returned in two 32-bit registers
8011// (edx:eax on ia32, r1:r0 on ARM).
8012// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8013// In Win64 calling convention, a struct of two pointers is returned in memory,
8014// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008015#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008016struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008017 MaybeObject* x;
8018 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008019};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008020
lrn@chromium.org303ada72010-10-27 09:33:13 +00008021static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008022 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008023 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8024 // In Win64 they are assigned to a hidden first argument.
8025 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008026}
8027#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008028typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008029static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008030 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008031 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008032}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008033#endif
8034
8035
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008036static inline MaybeObject* Unhole(Heap* heap,
8037 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008038 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008039 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8040 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008041 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008042}
8043
8044
danno@chromium.org40cb8782011-05-25 07:58:50 +00008045static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8046 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008047 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008048 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008049 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008050 JSFunction* context_extension_function =
8051 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008052 // If the holder isn't a context extension object, we just return it
8053 // as the receiver. This allows arguments objects to be used as
8054 // receivers, but only if they are put in the context scope chain
8055 // explicitly via a with-statement.
8056 Object* constructor = holder->map()->constructor();
8057 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008058 // Fall back to using the global object as the implicit receiver if
8059 // the property turns out to be a local variable allocated in a
8060 // context extension object - introduced via eval. Implicit global
8061 // receivers are indicated with the hole value.
8062 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008063}
8064
8065
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008066static ObjectPair LoadContextSlotHelper(Arguments args,
8067 Isolate* isolate,
8068 bool throw_error) {
8069 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008070 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008071
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008072 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008073 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008074 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008075 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008076 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008077
8078 int index;
8079 PropertyAttributes attributes;
8080 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008081 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008082
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008083 // If the index is non-negative, the slot has been found in a local
8084 // variable or a parameter. Read it from the context object or the
8085 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008086 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008087 // If the "property" we were looking for is a local variable or an
8088 // argument in a context, the receiver is the global object; see
8089 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008090 //
8091 // Use the hole as the receiver to signal that the receiver is
8092 // implicit and that the global receiver should be used.
8093 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008094 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008095 ? Context::cast(*holder)->get(index)
8096 : JSObject::cast(*holder)->GetElement(index);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008097 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008098 }
8099
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008100 // If the holder is found, we read the property from it.
8101 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008102 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008103 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008104 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008105 if (object->IsGlobalObject()) {
8106 receiver = GlobalObject::cast(object)->global_receiver();
8107 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008108 // Use the hole as the receiver to signal that the receiver is
8109 // implicit and that the global receiver should be used.
8110 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008111 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008112 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008113 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008114
8115 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008116 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008117
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008118 // No need to unhole the value here. This is taken care of by the
8119 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008120 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008121 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008122 }
8123
8124 if (throw_error) {
8125 // The property doesn't exist - throw exception.
8126 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008127 isolate->factory()->NewReferenceError("not_defined",
8128 HandleVector(&name, 1));
8129 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008130 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008131 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008132 return MakePair(isolate->heap()->undefined_value(),
8133 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008134 }
8135}
8136
8137
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008138RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008139 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008140}
8141
8142
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008143RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008144 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008145}
8146
8147
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008148RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008149 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008150 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008151
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008152 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008153 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008154 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008155 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008156 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8157 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008158 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008159
8160 int index;
8161 PropertyAttributes attributes;
8162 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008163 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008164
8165 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008166 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008167 // Ignore if read_only variable.
8168 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008169 // Context is a fixed array and set cannot fail.
8170 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008171 } else if (strict_mode == kStrictMode) {
8172 // Setting read only property in strict mode.
8173 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008174 isolate->factory()->NewTypeError("strict_cannot_assign",
8175 HandleVector(&name, 1));
8176 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008177 }
8178 } else {
8179 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008180 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008181 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008182 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008183 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008184 return Failure::Exception();
8185 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008186 }
8187 return *value;
8188 }
8189
8190 // Slow case: The property is not in a FixedArray context.
8191 // It is either in an JSObject extension context or it was not found.
8192 Handle<JSObject> context_ext;
8193
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008194 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008195 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008196 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008197 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008198 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008199 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008200
8201 if (strict_mode == kStrictMode) {
8202 // Throw in strict mode (assignment to undefined variable).
8203 Handle<Object> error =
8204 isolate->factory()->NewReferenceError(
8205 "not_defined", HandleVector(&name, 1));
8206 return isolate->Throw(*error);
8207 }
8208 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008209 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008210 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008211 }
8212
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008213 // Set the property, but ignore if read_only variable on the context
8214 // extension object itself.
8215 if ((attributes & READ_ONLY) == 0 ||
8216 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008217 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008218 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008219 SetProperty(context_ext, name, value, NONE, strict_mode));
8220 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008221 // Setting read only property in strict mode.
8222 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008223 isolate->factory()->NewTypeError(
8224 "strict_cannot_assign", HandleVector(&name, 1));
8225 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008226 }
8227 return *value;
8228}
8229
8230
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008231RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008232 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008233 ASSERT(args.length() == 1);
8234
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008235 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008236}
8237
8238
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008239RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008240 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008241 ASSERT(args.length() == 1);
8242
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008243 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008244}
8245
8246
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008247RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008248 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008249 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008250}
8251
8252
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008253RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008254 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008255 ASSERT(args.length() == 1);
8256
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008257 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008258 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008259 isolate->factory()->NewReferenceError("not_defined",
8260 HandleVector(&name, 1));
8261 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008262}
8263
8264
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008265RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008266 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008267
8268 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008269 if (isolate->stack_guard()->IsStackOverflow()) {
8270 NoHandleAllocation na;
8271 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008272 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008273
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008274 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008275}
8276
8277
8278// NOTE: These PrintXXX functions are defined for all builds (not just
8279// DEBUG builds) because we may want to be able to trace function
8280// calls in all modes.
8281static void PrintString(String* str) {
8282 // not uncommon to have empty strings
8283 if (str->length() > 0) {
8284 SmartPointer<char> s =
8285 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8286 PrintF("%s", *s);
8287 }
8288}
8289
8290
8291static void PrintObject(Object* obj) {
8292 if (obj->IsSmi()) {
8293 PrintF("%d", Smi::cast(obj)->value());
8294 } else if (obj->IsString() || obj->IsSymbol()) {
8295 PrintString(String::cast(obj));
8296 } else if (obj->IsNumber()) {
8297 PrintF("%g", obj->Number());
8298 } else if (obj->IsFailure()) {
8299 PrintF("<failure>");
8300 } else if (obj->IsUndefined()) {
8301 PrintF("<undefined>");
8302 } else if (obj->IsNull()) {
8303 PrintF("<null>");
8304 } else if (obj->IsTrue()) {
8305 PrintF("<true>");
8306 } else if (obj->IsFalse()) {
8307 PrintF("<false>");
8308 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008309 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008310 }
8311}
8312
8313
8314static int StackSize() {
8315 int n = 0;
8316 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8317 return n;
8318}
8319
8320
8321static void PrintTransition(Object* result) {
8322 // indentation
8323 { const int nmax = 80;
8324 int n = StackSize();
8325 if (n <= nmax)
8326 PrintF("%4d:%*s", n, n, "");
8327 else
8328 PrintF("%4d:%*s", n, nmax, "...");
8329 }
8330
8331 if (result == NULL) {
8332 // constructor calls
8333 JavaScriptFrameIterator it;
8334 JavaScriptFrame* frame = it.frame();
8335 if (frame->IsConstructor()) PrintF("new ");
8336 // function name
8337 Object* fun = frame->function();
8338 if (fun->IsJSFunction()) {
8339 PrintObject(JSFunction::cast(fun)->shared()->name());
8340 } else {
8341 PrintObject(fun);
8342 }
8343 // function arguments
8344 // (we are intentionally only printing the actually
8345 // supplied parameters, not all parameters required)
8346 PrintF("(this=");
8347 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008348 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008349 for (int i = 0; i < length; i++) {
8350 PrintF(", ");
8351 PrintObject(frame->GetParameter(i));
8352 }
8353 PrintF(") {\n");
8354
8355 } else {
8356 // function result
8357 PrintF("} -> ");
8358 PrintObject(result);
8359 PrintF("\n");
8360 }
8361}
8362
8363
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008364RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008365 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008366 NoHandleAllocation ha;
8367 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008368 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008369}
8370
8371
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008372RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008373 NoHandleAllocation ha;
8374 PrintTransition(args[0]);
8375 return args[0]; // return TOS
8376}
8377
8378
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008379RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008380 NoHandleAllocation ha;
8381 ASSERT(args.length() == 1);
8382
8383#ifdef DEBUG
8384 if (args[0]->IsString()) {
8385 // If we have a string, assume it's a code "marker"
8386 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008387 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008388 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008389 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8390 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008391 } else {
8392 PrintF("DebugPrint: ");
8393 }
8394 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008395 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008396 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008397 HeapObject::cast(args[0])->map()->Print();
8398 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008399#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008400 // ShortPrint is available in release mode. Print is not.
8401 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008402#endif
8403 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008404 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008405
8406 return args[0]; // return TOS
8407}
8408
8409
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008410RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008411 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008412 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008413 isolate->PrintStack();
8414 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008415}
8416
8417
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008418RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008419 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008420 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008421
8422 // According to ECMA-262, section 15.9.1, page 117, the precision of
8423 // the number in a Date object representing a particular instant in
8424 // time is milliseconds. Therefore, we floor the result of getting
8425 // the OS time.
8426 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008427 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008428}
8429
8430
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008431RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008432 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008433 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008434
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008435 CONVERT_ARG_CHECKED(String, str, 0);
8436 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008437
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008438 CONVERT_ARG_CHECKED(JSArray, output, 1);
8439 RUNTIME_ASSERT(output->HasFastElements());
8440
8441 AssertNoAllocation no_allocation;
8442
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008443 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008444 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8445 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008446 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008447 result = DateParser::Parse(str->ToAsciiVector(),
8448 output_array,
8449 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008450 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008451 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008452 result = DateParser::Parse(str->ToUC16Vector(),
8453 output_array,
8454 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008455 }
8456
8457 if (result) {
8458 return *output;
8459 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008460 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008461 }
8462}
8463
8464
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008465RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008466 NoHandleAllocation ha;
8467 ASSERT(args.length() == 1);
8468
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008469 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008470 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008471 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008472}
8473
8474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008475RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008476 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008477 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008478
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008479 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008480}
8481
8482
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008483RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008484 NoHandleAllocation ha;
8485 ASSERT(args.length() == 1);
8486
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008487 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008488 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008489}
8490
8491
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008492RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008493 ASSERT(args.length() == 1);
8494 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008495 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008496 return JSGlobalObject::cast(global)->global_receiver();
8497}
8498
8499
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008500RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008501 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008502 ASSERT_EQ(1, args.length());
8503 CONVERT_ARG_CHECKED(String, source, 0);
8504
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008505 source = Handle<String>(source->TryFlattenGetString());
8506 // Optimized fast case where we only have ascii characters.
8507 Handle<Object> result;
8508 if (source->IsSeqAsciiString()) {
8509 result = JsonParser<true>::Parse(source);
8510 } else {
8511 result = JsonParser<false>::Parse(source);
8512 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008513 if (result.is_null()) {
8514 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008515 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008516 return Failure::Exception();
8517 }
8518 return *result;
8519}
8520
8521
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008522bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8523 Handle<Context> context) {
8524 if (context->allow_code_gen_from_strings()->IsFalse()) {
8525 // Check with callback if set.
8526 AllowCodeGenerationFromStringsCallback callback =
8527 isolate->allow_code_gen_callback();
8528 if (callback == NULL) {
8529 // No callback set and code generation disallowed.
8530 return false;
8531 } else {
8532 // Callback set. Let it decide if code generation is allowed.
8533 VMState state(isolate, EXTERNAL);
8534 return callback(v8::Utils::ToLocal(context));
8535 }
8536 }
8537 return true;
8538}
8539
8540
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008541RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008542 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008543 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008544 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008545
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008546 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008547 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008548
8549 // Check if global context allows code generation from
8550 // strings. Throw an exception if it doesn't.
8551 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8552 return isolate->Throw(*isolate->factory()->NewError(
8553 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8554 }
8555
8556 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008557 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8558 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008559 true,
8560 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008561 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008562 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008563 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8564 context,
8565 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008566 return *fun;
8567}
8568
8569
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008570static ObjectPair CompileGlobalEval(Isolate* isolate,
8571 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008572 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008573 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008574 Handle<Context> context = Handle<Context>(isolate->context());
8575 Handle<Context> global_context = Handle<Context>(context->global_context());
8576
8577 // Check if global context allows code generation from
8578 // strings. Throw an exception if it doesn't.
8579 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8580 isolate->Throw(*isolate->factory()->NewError(
8581 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8582 return MakePair(Failure::Exception(), NULL);
8583 }
8584
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008585 // Deal with a normal eval call with a string argument. Compile it
8586 // and return the compiled function bound in the local context.
8587 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8588 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008589 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008590 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008591 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008592 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008593 Handle<JSFunction> compiled =
8594 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008595 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008596 return MakePair(*compiled, *receiver);
8597}
8598
8599
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008600RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008601 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008602
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008603 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008604 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008605 Handle<Object> receiver; // Will be overwritten.
8606
8607 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008608 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008609#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008610 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008611 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008612 StackFrameLocator locator;
8613 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008614 ASSERT(Context::cast(frame->context()) == *context);
8615#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008616
8617 // Find where the 'eval' symbol is bound. It is unaliased only if
8618 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008619 int index = -1;
8620 PropertyAttributes attributes = ABSENT;
8621 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008622 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8623 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008624 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008625 // Stop search when eval is found or when the global context is
8626 // reached.
8627 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008628 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008629 }
8630
iposva@chromium.org245aa852009-02-10 00:49:54 +00008631 // If eval could not be resolved, it has been deleted and we need to
8632 // throw a reference error.
8633 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008634 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008635 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008636 isolate->factory()->NewReferenceError("not_defined",
8637 HandleVector(&name, 1));
8638 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008639 }
8640
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008641 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008642 // 'eval' is not bound in the global context. Just call the function
8643 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00008644 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008645 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008646 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008647 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008648 }
8649
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008650 // 'eval' is bound in the global context, but it may have been overwritten.
8651 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008652 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008653 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008654 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008655 }
8656
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008657 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008658 return CompileGlobalEval(isolate,
8659 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008660 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008661 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008662}
8663
8664
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008665RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008666 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008667
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008668 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008669 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008670
8671 // 'eval' is bound in the global context, but it may have been overwritten.
8672 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008673 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008674 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008675 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008676 }
8677
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008678 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008679 return CompileGlobalEval(isolate,
8680 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008681 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008682 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008683}
8684
8685
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008686RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008687 // This utility adjusts the property attributes for newly created Function
8688 // object ("new Function(...)") by changing the map.
8689 // All it does is changing the prototype property to enumerable
8690 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008691 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008692 ASSERT(args.length() == 1);
8693 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008694
8695 Handle<Map> map = func->shared()->strict_mode()
8696 ? isolate->strict_mode_function_instance_map()
8697 : isolate->function_instance_map();
8698
8699 ASSERT(func->map()->instance_type() == map->instance_type());
8700 ASSERT(func->map()->instance_size() == map->instance_size());
8701 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008702 return *func;
8703}
8704
8705
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008706RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008707 // Allocate a block of memory in NewSpace (filled with a filler).
8708 // Use as fallback for allocation in generated code when NewSpace
8709 // is full.
8710 ASSERT(args.length() == 1);
8711 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8712 int size = size_smi->value();
8713 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8714 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008715 Heap* heap = isolate->heap();
8716 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008717 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008718 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008719 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008720 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008721 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008722 }
8723 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008724 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008725}
8726
8727
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008728// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008729// array. Returns true if the element was pushed on the stack and
8730// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008731RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008732 ASSERT(args.length() == 2);
8733 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008734 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008735 RUNTIME_ASSERT(array->HasFastElements());
8736 int length = Smi::cast(array->length())->value();
8737 FixedArray* elements = FixedArray::cast(array->elements());
8738 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008739 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008740 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008741 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008742 // Strict not needed. Used for cycle detection in Array join implementation.
8743 { MaybeObject* maybe_obj = array->SetFastElement(length, element,
8744 kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008745 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8746 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008747 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008748}
8749
8750
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008751/**
8752 * A simple visitor visits every element of Array's.
8753 * The backend storage can be a fixed array for fast elements case,
8754 * or a dictionary for sparse array. Since Dictionary is a subtype
8755 * of FixedArray, the class can be used by both fast and slow cases.
8756 * The second parameter of the constructor, fast_elements, specifies
8757 * whether the storage is a FixedArray or Dictionary.
8758 *
8759 * An index limit is used to deal with the situation that a result array
8760 * length overflows 32-bit non-negative integer.
8761 */
8762class ArrayConcatVisitor {
8763 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008764 ArrayConcatVisitor(Isolate* isolate,
8765 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008766 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008767 isolate_(isolate),
8768 storage_(Handle<FixedArray>::cast(
8769 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008770 index_offset_(0u),
8771 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008772
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008773 ~ArrayConcatVisitor() {
8774 clear_storage();
8775 }
8776
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008777 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008778 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008779 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008780
8781 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008782 if (index < static_cast<uint32_t>(storage_->length())) {
8783 storage_->set(index, *elm);
8784 return;
8785 }
8786 // Our initial estimate of length was foiled, possibly by
8787 // getters on the arrays increasing the length of later arrays
8788 // during iteration.
8789 // This shouldn't happen in anything but pathological cases.
8790 SetDictionaryMode(index);
8791 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008792 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008793 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008794 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008795 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008796 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008797 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008798 // Dictionary needed to grow.
8799 clear_storage();
8800 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008801 }
8802}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008803
8804 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008805 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8806 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008807 } else {
8808 index_offset_ += delta;
8809 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008810 }
8811
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008812 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008813 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008814 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008815 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008816 Handle<Map> map;
8817 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008818 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008819 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008820 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008821 }
8822 array->set_map(*map);
8823 array->set_length(*length);
8824 array->set_elements(*storage_);
8825 return array;
8826 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008827
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008828 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008829 // Convert storage to dictionary mode.
8830 void SetDictionaryMode(uint32_t index) {
8831 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008832 Handle<FixedArray> current_storage(*storage_);
8833 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008834 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008835 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8836 for (uint32_t i = 0; i < current_length; i++) {
8837 HandleScope loop_scope;
8838 Handle<Object> element(current_storage->get(i));
8839 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008840 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008841 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008842 if (!new_storage.is_identical_to(slow_storage)) {
8843 slow_storage = loop_scope.CloseAndEscape(new_storage);
8844 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008845 }
8846 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008847 clear_storage();
8848 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008849 fast_elements_ = false;
8850 }
8851
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008852 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008853 isolate_->global_handles()->Destroy(
8854 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008855 }
8856
8857 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008858 storage_ = Handle<FixedArray>::cast(
8859 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008860 }
8861
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008862 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008863 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008864 // Index after last seen index. Always less than or equal to
8865 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008866 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008867 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008868};
8869
8870
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008871static uint32_t EstimateElementCount(Handle<JSArray> array) {
8872 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8873 int element_count = 0;
8874 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008875 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008876 // Fast elements can't have lengths that are not representable by
8877 // a 32-bit signed integer.
8878 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8879 int fast_length = static_cast<int>(length);
8880 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8881 for (int i = 0; i < fast_length; i++) {
8882 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008883 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008884 break;
8885 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008886 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008887 Handle<NumberDictionary> dictionary(
8888 NumberDictionary::cast(array->elements()));
8889 int capacity = dictionary->Capacity();
8890 for (int i = 0; i < capacity; i++) {
8891 Handle<Object> key(dictionary->KeyAt(i));
8892 if (dictionary->IsKey(*key)) {
8893 element_count++;
8894 }
8895 }
8896 break;
8897 }
8898 default:
8899 // External arrays are always dense.
8900 return length;
8901 }
8902 // As an estimate, we assume that the prototype doesn't contain any
8903 // inherited elements.
8904 return element_count;
8905}
8906
8907
8908
8909template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008910static void IterateExternalArrayElements(Isolate* isolate,
8911 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008912 bool elements_are_ints,
8913 bool elements_are_guaranteed_smis,
8914 ArrayConcatVisitor* visitor) {
8915 Handle<ExternalArrayClass> array(
8916 ExternalArrayClass::cast(receiver->elements()));
8917 uint32_t len = static_cast<uint32_t>(array->length());
8918
8919 ASSERT(visitor != NULL);
8920 if (elements_are_ints) {
8921 if (elements_are_guaranteed_smis) {
8922 for (uint32_t j = 0; j < len; j++) {
8923 HandleScope loop_scope;
8924 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8925 visitor->visit(j, e);
8926 }
8927 } else {
8928 for (uint32_t j = 0; j < len; j++) {
8929 HandleScope loop_scope;
8930 int64_t val = static_cast<int64_t>(array->get(j));
8931 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8932 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8933 visitor->visit(j, e);
8934 } else {
8935 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008936 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008937 visitor->visit(j, e);
8938 }
8939 }
8940 }
8941 } else {
8942 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008943 HandleScope loop_scope(isolate);
8944 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008945 visitor->visit(j, e);
8946 }
8947 }
8948}
8949
8950
8951// Used for sorting indices in a List<uint32_t>.
8952static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8953 uint32_t a = *ap;
8954 uint32_t b = *bp;
8955 return (a == b) ? 0 : (a < b) ? -1 : 1;
8956}
8957
8958
8959static void CollectElementIndices(Handle<JSObject> object,
8960 uint32_t range,
8961 List<uint32_t>* indices) {
8962 JSObject::ElementsKind kind = object->GetElementsKind();
8963 switch (kind) {
8964 case JSObject::FAST_ELEMENTS: {
8965 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8966 uint32_t length = static_cast<uint32_t>(elements->length());
8967 if (range < length) length = range;
8968 for (uint32_t i = 0; i < length; i++) {
8969 if (!elements->get(i)->IsTheHole()) {
8970 indices->Add(i);
8971 }
8972 }
8973 break;
8974 }
8975 case JSObject::DICTIONARY_ELEMENTS: {
8976 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008977 uint32_t capacity = dict->Capacity();
8978 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008979 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008980 Handle<Object> k(dict->KeyAt(j));
8981 if (dict->IsKey(*k)) {
8982 ASSERT(k->IsNumber());
8983 uint32_t index = static_cast<uint32_t>(k->Number());
8984 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008985 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008986 }
8987 }
8988 }
8989 break;
8990 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008991 default: {
8992 int dense_elements_length;
8993 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008994 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008995 dense_elements_length =
8996 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008997 break;
8998 }
8999 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009000 dense_elements_length =
9001 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009002 break;
9003 }
9004 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009005 dense_elements_length =
9006 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009007 break;
9008 }
9009 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009010 dense_elements_length =
9011 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009012 break;
9013 }
9014 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009015 dense_elements_length =
9016 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009017 break;
9018 }
9019 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009020 dense_elements_length =
9021 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009022 break;
9023 }
9024 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009025 dense_elements_length =
9026 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009027 break;
9028 }
9029 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009030 dense_elements_length =
9031 ExternalFloatArray::cast(object->elements())->length();
9032 break;
9033 }
9034 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9035 dense_elements_length =
9036 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009037 break;
9038 }
9039 default:
9040 UNREACHABLE();
9041 dense_elements_length = 0;
9042 break;
9043 }
9044 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9045 if (range <= length) {
9046 length = range;
9047 // We will add all indices, so we might as well clear it first
9048 // and avoid duplicates.
9049 indices->Clear();
9050 }
9051 for (uint32_t i = 0; i < length; i++) {
9052 indices->Add(i);
9053 }
9054 if (length == range) return; // All indices accounted for already.
9055 break;
9056 }
9057 }
9058
9059 Handle<Object> prototype(object->GetPrototype());
9060 if (prototype->IsJSObject()) {
9061 // The prototype will usually have no inherited element indices,
9062 // but we have to check.
9063 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9064 }
9065}
9066
9067
9068/**
9069 * A helper function that visits elements of a JSArray in numerical
9070 * order.
9071 *
9072 * The visitor argument called for each existing element in the array
9073 * with the element index and the element's value.
9074 * Afterwards it increments the base-index of the visitor by the array
9075 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009076 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009077 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009078static bool IterateElements(Isolate* isolate,
9079 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009080 ArrayConcatVisitor* visitor) {
9081 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9082 switch (receiver->GetElementsKind()) {
9083 case JSObject::FAST_ELEMENTS: {
9084 // Run through the elements FixedArray and use HasElement and GetElement
9085 // to check the prototype for missing elements.
9086 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9087 int fast_length = static_cast<int>(length);
9088 ASSERT(fast_length <= elements->length());
9089 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009090 HandleScope loop_scope(isolate);
9091 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009092 if (!element_value->IsTheHole()) {
9093 visitor->visit(j, element_value);
9094 } else if (receiver->HasElement(j)) {
9095 // Call GetElement on receiver, not its prototype, or getters won't
9096 // have the correct receiver.
9097 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009098 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009099 visitor->visit(j, element_value);
9100 }
9101 }
9102 break;
9103 }
9104 case JSObject::DICTIONARY_ELEMENTS: {
9105 Handle<NumberDictionary> dict(receiver->element_dictionary());
9106 List<uint32_t> indices(dict->Capacity() / 2);
9107 // Collect all indices in the object and the prototypes less
9108 // than length. This might introduce duplicates in the indices list.
9109 CollectElementIndices(receiver, length, &indices);
9110 indices.Sort(&compareUInt32);
9111 int j = 0;
9112 int n = indices.length();
9113 while (j < n) {
9114 HandleScope loop_scope;
9115 uint32_t index = indices[j];
9116 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009117 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009118 visitor->visit(index, element);
9119 // Skip to next different index (i.e., omit duplicates).
9120 do {
9121 j++;
9122 } while (j < n && indices[j] == index);
9123 }
9124 break;
9125 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009126 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
9127 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9128 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009129 for (uint32_t j = 0; j < length; j++) {
9130 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
9131 visitor->visit(j, e);
9132 }
9133 break;
9134 }
9135 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
9136 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009137 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009138 break;
9139 }
9140 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9141 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009142 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009143 break;
9144 }
9145 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
9146 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009147 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009148 break;
9149 }
9150 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9151 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009152 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009153 break;
9154 }
9155 case JSObject::EXTERNAL_INT_ELEMENTS: {
9156 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009157 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009158 break;
9159 }
9160 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9161 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009162 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009163 break;
9164 }
9165 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9166 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009167 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009168 break;
9169 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009170 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9171 IterateExternalArrayElements<ExternalDoubleArray, double>(
9172 isolate, receiver, false, false, visitor);
9173 break;
9174 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009175 default:
9176 UNREACHABLE();
9177 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009178 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009179 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009180 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009181}
9182
9183
9184/**
9185 * Array::concat implementation.
9186 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009187 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009188 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009189 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009190RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009191 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009192 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009193
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009194 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9195 int argument_count = static_cast<int>(arguments->length()->Number());
9196 RUNTIME_ASSERT(arguments->HasFastElements());
9197 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009198
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009199 // Pass 1: estimate the length and number of elements of the result.
9200 // The actual length can be larger if any of the arguments have getters
9201 // that mutate other arguments (but will otherwise be precise).
9202 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009203
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009204 uint32_t estimate_result_length = 0;
9205 uint32_t estimate_nof_elements = 0;
9206 {
9207 for (int i = 0; i < argument_count; i++) {
9208 HandleScope loop_scope;
9209 Handle<Object> obj(elements->get(i));
9210 uint32_t length_estimate;
9211 uint32_t element_estimate;
9212 if (obj->IsJSArray()) {
9213 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9214 length_estimate =
9215 static_cast<uint32_t>(array->length()->Number());
9216 element_estimate =
9217 EstimateElementCount(array);
9218 } else {
9219 length_estimate = 1;
9220 element_estimate = 1;
9221 }
9222 // Avoid overflows by capping at kMaxElementCount.
9223 if (JSObject::kMaxElementCount - estimate_result_length <
9224 length_estimate) {
9225 estimate_result_length = JSObject::kMaxElementCount;
9226 } else {
9227 estimate_result_length += length_estimate;
9228 }
9229 if (JSObject::kMaxElementCount - estimate_nof_elements <
9230 element_estimate) {
9231 estimate_nof_elements = JSObject::kMaxElementCount;
9232 } else {
9233 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009234 }
9235 }
9236 }
9237
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009238 // If estimated number of elements is more than half of length, a
9239 // fixed array (fast case) is more time and space-efficient than a
9240 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009241 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009242
9243 Handle<FixedArray> storage;
9244 if (fast_case) {
9245 // The backing storage array must have non-existing elements to
9246 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009247 storage = isolate->factory()->NewFixedArrayWithHoles(
9248 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009249 } else {
9250 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9251 uint32_t at_least_space_for = estimate_nof_elements +
9252 (estimate_nof_elements >> 2);
9253 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009254 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009255 }
9256
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009257 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009258
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009259 for (int i = 0; i < argument_count; i++) {
9260 Handle<Object> obj(elements->get(i));
9261 if (obj->IsJSArray()) {
9262 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009263 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009264 return Failure::Exception();
9265 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009266 } else {
9267 visitor.visit(0, obj);
9268 visitor.increase_index_offset(1);
9269 }
9270 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009271
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009272 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009273}
9274
9275
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009276// This will not allocate (flatten the string), but it may run
9277// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009278RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009279 NoHandleAllocation ha;
9280 ASSERT(args.length() == 1);
9281
9282 CONVERT_CHECKED(String, string, args[0]);
9283 StringInputBuffer buffer(string);
9284 while (buffer.has_more()) {
9285 uint16_t character = buffer.GetNext();
9286 PrintF("%c", character);
9287 }
9288 return string;
9289}
9290
ager@chromium.org5ec48922009-05-05 07:25:34 +00009291// Moves all own elements of an object, that are below a limit, to positions
9292// starting at zero. All undefined values are placed after non-undefined values,
9293// and are followed by non-existing element. Does not change the length
9294// property.
9295// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009296RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009297 ASSERT(args.length() == 2);
9298 CONVERT_CHECKED(JSObject, object, args[0]);
9299 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9300 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009301}
9302
9303
9304// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009305RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009306 ASSERT(args.length() == 2);
9307 CONVERT_CHECKED(JSArray, from, args[0]);
9308 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009309 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009310 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009311 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9312 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009313 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009314 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009315 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009316 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009317 Object* new_map;
9318 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009319 to->set_map(Map::cast(new_map));
9320 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009321 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009322 Object* obj;
9323 { MaybeObject* maybe_obj = from->ResetElements();
9324 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9325 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009326 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009327 return to;
9328}
9329
9330
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009331// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009332RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009333 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009334 CONVERT_CHECKED(JSObject, object, args[0]);
9335 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009336 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009337 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009338 } else if (object->IsJSArray()) {
9339 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009340 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009341 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009342 }
9343}
9344
9345
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009346RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009347 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009348
9349 ASSERT_EQ(3, args.length());
9350
ager@chromium.orgac091b72010-05-05 07:34:42 +00009351 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009352 Handle<Object> key1 = args.at<Object>(1);
9353 Handle<Object> key2 = args.at<Object>(2);
9354
9355 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009356 if (!key1->ToArrayIndex(&index1)
9357 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009358 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009359 }
9360
ager@chromium.orgac091b72010-05-05 07:34:42 +00009361 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9362 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009363 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009364 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009365 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009366
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009367 RETURN_IF_EMPTY_HANDLE(isolate,
9368 SetElement(jsobject, index1, tmp2, kStrictMode));
9369 RETURN_IF_EMPTY_HANDLE(isolate,
9370 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009371
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009372 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009373}
9374
9375
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009376// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009377// might have elements. Can either return keys (positive integers) or
9378// intervals (pair of a negative integer (-start-1) followed by a
9379// positive (length)) or undefined values.
9380// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009381RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009382 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009383 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009384 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009385 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009386 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009387 // Create an array and get all the keys into it, then remove all the
9388 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009389 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009390 int keys_length = keys->length();
9391 for (int i = 0; i < keys_length; i++) {
9392 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009393 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009394 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009395 // Zap invalid keys.
9396 keys->set_undefined(i);
9397 }
9398 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009399 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009400 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009401 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009402 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009403 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009404 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009405 uint32_t actual_length =
9406 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009407 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009408 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009409 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009410 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009411 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009412 }
9413}
9414
9415
9416// DefineAccessor takes an optional final argument which is the
9417// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9418// to the way accessors are implemented, it is set for both the getter
9419// and setter on the first call to DefineAccessor and ignored on
9420// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009421RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009422 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9423 // Compute attributes.
9424 PropertyAttributes attributes = NONE;
9425 if (args.length() == 5) {
9426 CONVERT_CHECKED(Smi, attrs, args[4]);
9427 int value = attrs->value();
9428 // Only attribute bits should be set.
9429 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9430 attributes = static_cast<PropertyAttributes>(value);
9431 }
9432
9433 CONVERT_CHECKED(JSObject, obj, args[0]);
9434 CONVERT_CHECKED(String, name, args[1]);
9435 CONVERT_CHECKED(Smi, flag, args[2]);
9436 CONVERT_CHECKED(JSFunction, fun, args[3]);
9437 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9438}
9439
9440
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009441RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009442 ASSERT(args.length() == 3);
9443 CONVERT_CHECKED(JSObject, obj, args[0]);
9444 CONVERT_CHECKED(String, name, args[1]);
9445 CONVERT_CHECKED(Smi, flag, args[2]);
9446 return obj->LookupAccessor(name, flag->value() == 0);
9447}
9448
9449
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009450#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009451RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009452 ASSERT(args.length() == 0);
9453 return Execution::DebugBreakHelper();
9454}
9455
9456
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009457// Helper functions for wrapping and unwrapping stack frame ids.
9458static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009459 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009460 return Smi::FromInt(id >> 2);
9461}
9462
9463
9464static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9465 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9466}
9467
9468
9469// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009470// args[0]: debug event listener function to set or null or undefined for
9471// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009472// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009473RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009474 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009475 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9476 args[0]->IsUndefined() ||
9477 args[0]->IsNull());
9478 Handle<Object> callback = args.at<Object>(0);
9479 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009480 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009481
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009482 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009483}
9484
9485
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009486RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009487 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009488 isolate->stack_guard()->DebugBreak();
9489 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009490}
9491
9492
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009493static MaybeObject* DebugLookupResultValue(Heap* heap,
9494 Object* receiver,
9495 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009496 LookupResult* result,
9497 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009498 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009499 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009500 case NORMAL:
9501 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009502 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009503 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009504 }
9505 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009506 case FIELD:
9507 value =
9508 JSObject::cast(
9509 result->holder())->FastPropertyAt(result->GetFieldIndex());
9510 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009511 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009512 }
9513 return value;
9514 case CONSTANT_FUNCTION:
9515 return result->GetConstantFunction();
9516 case CALLBACKS: {
9517 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009518 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009519 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009520 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009521 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009522 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009523 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009524 maybe_value = heap->isolate()->pending_exception();
9525 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009526 if (caught_exception != NULL) {
9527 *caught_exception = true;
9528 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009529 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009530 }
9531 return value;
9532 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009533 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009534 }
9535 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009536 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009537 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009538 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009539 case CONSTANT_TRANSITION:
9540 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009541 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009542 default:
9543 UNREACHABLE();
9544 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009545 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009546 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009547}
9548
9549
ager@chromium.org32912102009-01-16 10:38:43 +00009550// Get debugger related details for an object property.
9551// args[0]: object holding property
9552// args[1]: name of the property
9553//
9554// The array returned contains the following information:
9555// 0: Property value
9556// 1: Property details
9557// 2: Property value is exception
9558// 3: Getter function if defined
9559// 4: Setter function if defined
9560// Items 2-4 are only filled if the property has either a getter or a setter
9561// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009562RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009563 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009564
9565 ASSERT(args.length() == 2);
9566
9567 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9568 CONVERT_ARG_CHECKED(String, name, 1);
9569
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009570 // Make sure to set the current context to the context before the debugger was
9571 // entered (if the debugger is entered). The reason for switching context here
9572 // is that for some property lookups (accessors and interceptors) callbacks
9573 // into the embedding application can occour, and the embedding application
9574 // could have the assumption that its own global context is the current
9575 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009576 SaveContext save(isolate);
9577 if (isolate->debug()->InDebugger()) {
9578 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009579 }
9580
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009581 // Skip the global proxy as it has no properties and always delegates to the
9582 // real global object.
9583 if (obj->IsJSGlobalProxy()) {
9584 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9585 }
9586
9587
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009588 // Check if the name is trivially convertible to an index and get the element
9589 // if so.
9590 uint32_t index;
9591 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009592 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009593 Object* element_or_char;
9594 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009595 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009596 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9597 return maybe_element_or_char;
9598 }
9599 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009600 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009601 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009602 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009603 }
9604
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009605 // Find the number of objects making up this.
9606 int length = LocalPrototypeChainLength(*obj);
9607
9608 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009609 Handle<JSObject> jsproto = obj;
9610 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009611 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009612 jsproto->LocalLookup(*name, &result);
9613 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009614 // LookupResult is not GC safe as it holds raw object pointers.
9615 // GC can happen later in this code so put the required fields into
9616 // local variables using handles when required for later use.
9617 PropertyType result_type = result.type();
9618 Handle<Object> result_callback_obj;
9619 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009620 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9621 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009622 }
9623 Smi* property_details = result.GetPropertyDetails().AsSmi();
9624 // DebugLookupResultValue can cause GC so details from LookupResult needs
9625 // to be copied to handles before this.
9626 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009627 Object* raw_value;
9628 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009629 DebugLookupResultValue(isolate->heap(), *obj, *name,
9630 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009631 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9632 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009633 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009634
9635 // If the callback object is a fixed array then it contains JavaScript
9636 // getter and/or setter.
9637 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9638 result_callback_obj->IsFixedArray();
9639 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009640 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009641 details->set(0, *value);
9642 details->set(1, property_details);
9643 if (hasJavaScriptAccessors) {
9644 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009645 caught_exception ? isolate->heap()->true_value()
9646 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009647 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9648 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9649 }
9650
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009651 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009652 }
9653 if (i < length - 1) {
9654 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9655 }
9656 }
9657
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009658 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009659}
9660
9661
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009662RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009663 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009664
9665 ASSERT(args.length() == 2);
9666
9667 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9668 CONVERT_ARG_CHECKED(String, name, 1);
9669
9670 LookupResult result;
9671 obj->Lookup(*name, &result);
9672 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009673 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009674 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009675 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009676}
9677
9678
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009679// Return the property type calculated from the property details.
9680// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009681RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009682 ASSERT(args.length() == 1);
9683 CONVERT_CHECKED(Smi, details, args[0]);
9684 PropertyType type = PropertyDetails(details).type();
9685 return Smi::FromInt(static_cast<int>(type));
9686}
9687
9688
9689// Return the property attribute calculated from the property details.
9690// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009691RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009692 ASSERT(args.length() == 1);
9693 CONVERT_CHECKED(Smi, details, args[0]);
9694 PropertyAttributes attributes = PropertyDetails(details).attributes();
9695 return Smi::FromInt(static_cast<int>(attributes));
9696}
9697
9698
9699// Return the property insertion index calculated from the property details.
9700// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009701RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009702 ASSERT(args.length() == 1);
9703 CONVERT_CHECKED(Smi, details, args[0]);
9704 int index = PropertyDetails(details).index();
9705 return Smi::FromInt(index);
9706}
9707
9708
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009709// Return property value from named interceptor.
9710// args[0]: object
9711// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009712RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009713 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009714 ASSERT(args.length() == 2);
9715 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9716 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9717 CONVERT_ARG_CHECKED(String, name, 1);
9718
9719 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009720 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009721}
9722
9723
9724// Return element value from indexed interceptor.
9725// args[0]: object
9726// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009727RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009728 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009729 ASSERT(args.length() == 2);
9730 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9731 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9732 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9733
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009734 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009735}
9736
9737
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009738RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009739 ASSERT(args.length() >= 1);
9740 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009741 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009742 if (isolate->debug()->break_id() == 0 ||
9743 break_id != isolate->debug()->break_id()) {
9744 return isolate->Throw(
9745 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009746 }
9747
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009748 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009749}
9750
9751
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009752RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009753 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009754 ASSERT(args.length() == 1);
9755
9756 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009757 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009758 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9759 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009760 if (!maybe_result->ToObject(&result)) return maybe_result;
9761 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009762
9763 // Count all frames which are relevant to debugging stack trace.
9764 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009765 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009766 if (id == StackFrame::NO_ID) {
9767 // If there is no JavaScript stack frame count is 0.
9768 return Smi::FromInt(0);
9769 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009770 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009771 return Smi::FromInt(n);
9772}
9773
9774
9775static const int kFrameDetailsFrameIdIndex = 0;
9776static const int kFrameDetailsReceiverIndex = 1;
9777static const int kFrameDetailsFunctionIndex = 2;
9778static const int kFrameDetailsArgumentCountIndex = 3;
9779static const int kFrameDetailsLocalCountIndex = 4;
9780static const int kFrameDetailsSourcePositionIndex = 5;
9781static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009782static const int kFrameDetailsAtReturnIndex = 7;
9783static const int kFrameDetailsDebuggerFrameIndex = 8;
9784static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009785
9786// Return an array with frame details
9787// args[0]: number: break id
9788// args[1]: number: frame index
9789//
9790// The array returned contains the following information:
9791// 0: Frame id
9792// 1: Receiver
9793// 2: Function
9794// 3: Argument count
9795// 4: Local count
9796// 5: Source position
9797// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009798// 7: Is at return
9799// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009800// Arguments name, value
9801// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009802// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009803RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009804 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009805 ASSERT(args.length() == 2);
9806
9807 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009808 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009809 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
9810 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009811 if (!maybe_check->ToObject(&check)) return maybe_check;
9812 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009813 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009814 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009815
9816 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009817 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009818 if (id == StackFrame::NO_ID) {
9819 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009820 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009821 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009822 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009823 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009824 for (; !it.done(); it.Advance()) {
9825 if (count == index) break;
9826 count++;
9827 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009828 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009829
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009830 bool is_optimized_frame =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009831 it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009832
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009833 // Traverse the saved contexts chain to find the active context for the
9834 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009835 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009836 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009837 save = save->prev();
9838 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009839 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009840
9841 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009842 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009843
9844 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009845 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009846 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009847
9848 // Check for constructor frame.
9849 bool constructor = it.frame()->IsConstructor();
9850
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009851 // Get scope info and read from it for local variable information.
9852 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009853 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009854 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009855
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009856 // Get the nearest enclosing function context.
9857 Handle<Context> context(Context::cast(it.frame()->context())->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009858
9859 // Get the locals names and values into a temporary array.
9860 //
9861 // TODO(1240907): Hide compiler-introduced stack variables
9862 // (e.g. .result)? For users of the debugger, they will probably be
9863 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009864 Handle<FixedArray> locals =
9865 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009866
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009867 // Fill in the names of the locals.
9868 for (int i = 0; i < info.NumberOfLocals(); i++) {
9869 locals->set(i * 2, *info.LocalName(i));
9870 }
9871
9872 // Fill in the values of the locals.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009873 if (is_optimized_frame) {
9874 // If we are inspecting an optimized frame use undefined as the
9875 // value for all locals.
9876 //
9877 // TODO(1140): We should be able to get the correct values
9878 // for locals in optimized frames.
9879 for (int i = 0; i < info.NumberOfLocals(); i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009880 locals->set(i * 2 + 1, isolate->heap()->undefined_value());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009881 }
9882 } else {
9883 for (int i = 0; i < info.number_of_stack_slots(); i++) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009884 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009885 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009886 }
9887 for (int i = info.number_of_stack_slots(); i < info.NumberOfLocals(); i++) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009888 Handle<String> name = info.LocalName(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009889 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009890 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009891 }
9892 }
9893
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009894 // Check whether this frame is positioned at return. If not top
9895 // frame or if the frame is optimized it cannot be at a return.
9896 bool at_return = false;
9897 if (!is_optimized_frame && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009898 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009899 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009900
9901 // If positioned just before return find the value to be returned and add it
9902 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009903 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009904 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009905 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009906 Address internal_frame_sp = NULL;
9907 while (!it2.done()) {
9908 if (it2.frame()->is_internal()) {
9909 internal_frame_sp = it2.frame()->sp();
9910 } else {
9911 if (it2.frame()->is_java_script()) {
9912 if (it2.frame()->id() == it.frame()->id()) {
9913 // The internal frame just before the JavaScript frame contains the
9914 // value to return on top. A debug break at return will create an
9915 // internal frame to store the return value (eax/rax/r0) before
9916 // entering the debug break exit frame.
9917 if (internal_frame_sp != NULL) {
9918 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009919 Handle<Object>(Memory::Object_at(internal_frame_sp),
9920 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009921 break;
9922 }
9923 }
9924 }
9925
9926 // Indicate that the previous frame was not an internal frame.
9927 internal_frame_sp = NULL;
9928 }
9929 it2.Advance();
9930 }
9931 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009932
9933 // Now advance to the arguments adapter frame (if any). It contains all
9934 // the provided parameters whereas the function frame always have the number
9935 // of arguments matching the functions parameters. The rest of the
9936 // information (except for what is collected above) is the same.
9937 it.AdvanceToArgumentsFrame();
9938
9939 // Find the number of arguments to fill. At least fill the number of
9940 // parameters for the function and fill more if more parameters are provided.
9941 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009942 if (argument_count < it.frame()->ComputeParametersCount()) {
9943 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009944 }
9945
9946 // Calculate the size of the result.
9947 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009948 2 * (argument_count + info.NumberOfLocals()) +
9949 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009950 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009951
9952 // Add the frame id.
9953 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9954
9955 // Add the function (same as in function frame).
9956 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9957
9958 // Add the arguments count.
9959 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9960
9961 // Add the locals count
9962 details->set(kFrameDetailsLocalCountIndex,
9963 Smi::FromInt(info.NumberOfLocals()));
9964
9965 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009966 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009967 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9968 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009969 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009970 }
9971
9972 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009973 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009974
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009975 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009976 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009977
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009978 // Add information on whether this frame is invoked in the debugger context.
9979 details->set(kFrameDetailsDebuggerFrameIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009980 heap->ToBoolean(*save->context() ==
9981 *isolate->debug()->debug_context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009982
9983 // Fill the dynamic part.
9984 int details_index = kFrameDetailsFirstDynamicIndex;
9985
9986 // Add arguments name and value.
9987 for (int i = 0; i < argument_count; i++) {
9988 // Name of the argument.
9989 if (i < info.number_of_parameters()) {
9990 details->set(details_index++, *info.parameter_name(i));
9991 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009992 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009993 }
9994
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009995 // Parameter value. If we are inspecting an optimized frame, use
9996 // undefined as the value.
9997 //
9998 // TODO(3141533): We should be able to get the actual parameter
9999 // value for optimized frames.
10000 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010001 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010002 details->set(details_index++, it.frame()->GetParameter(i));
10003 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010004 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010005 }
10006 }
10007
10008 // Add locals name and value from the temporary copy from the function frame.
10009 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10010 details->set(details_index++, locals->get(i));
10011 }
10012
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010013 // Add the value being returned.
10014 if (at_return) {
10015 details->set(details_index++, *return_value);
10016 }
10017
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010018 // Add the receiver (same as in function frame).
10019 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10020 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010021 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010022 if (!receiver->IsJSObject()) {
10023 // If the receiver is NOT a JSObject we have hit an optimization
10024 // where a value object is not converted into a wrapped JS objects.
10025 // To hide this optimization from the debugger, we wrap the receiver
10026 // by creating correct wrapper object based on the calling frame's
10027 // global context.
10028 it.Advance();
10029 Handle<Context> calling_frames_global_context(
10030 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010031 receiver =
10032 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010033 }
10034 details->set(kFrameDetailsReceiverIndex, *receiver);
10035
10036 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010037 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010038}
10039
10040
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010041// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010042static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010043 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010044 Handle<SerializedScopeInfo> serialized_scope_info,
10045 ScopeInfo<>& scope_info,
10046 Handle<Context> context,
10047 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010048 // Fill all context locals to the context extension.
10049 for (int i = Context::MIN_CONTEXT_SLOTS;
10050 i < scope_info.number_of_context_slots();
10051 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010052 int context_index = serialized_scope_info->ContextSlotIndex(
10053 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010054
10055 // Don't include the arguments shadow (.arguments) context variable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010056 if (*scope_info.context_slot_name(i) !=
10057 isolate->heap()->arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010058 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010059 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010060 SetProperty(scope_object,
10061 scope_info.context_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010062 Handle<Object>(context->get(context_index), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010063 NONE,
10064 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010065 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010066 }
10067 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010068
10069 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010070}
10071
10072
10073// Create a plain JSObject which materializes the local scope for the specified
10074// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010075static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
10076 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010077 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010078 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010079 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10080 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010081
10082 // Allocate and initialize a JSObject with all the arguments, stack locals
10083 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010084 Handle<JSObject> local_scope =
10085 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010086
10087 // First fill all parameters.
10088 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010089 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010090 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010091 SetProperty(local_scope,
10092 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010093 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010094 NONE,
10095 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010096 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010097 }
10098
10099 // Second fill all stack locals.
10100 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010101 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010102 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010103 SetProperty(local_scope,
10104 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010105 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010106 NONE,
10107 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010108 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010109 }
10110
10111 // Third fill all context locals.
10112 Handle<Context> frame_context(Context::cast(frame->context()));
10113 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010114 if (!CopyContextLocalsToScopeObject(isolate,
10115 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010116 function_context, local_scope)) {
10117 return Handle<JSObject>();
10118 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010119
10120 // Finally copy any properties from the function context extension. This will
10121 // be variables introduced by eval.
10122 if (function_context->closure() == *function) {
10123 if (function_context->has_extension() &&
10124 !function_context->IsGlobalContext()) {
10125 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010126 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010127 for (int i = 0; i < keys->length(); i++) {
10128 // Names of variables introduced by eval are strings.
10129 ASSERT(keys->get(i)->IsString());
10130 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010131 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010132 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010133 SetProperty(local_scope,
10134 key,
10135 GetProperty(ext, key),
10136 NONE,
10137 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010138 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010139 }
10140 }
10141 }
10142 return local_scope;
10143}
10144
10145
10146// Create a plain JSObject which materializes the closure content for the
10147// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010148static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10149 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010150 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010151
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010152 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010153 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10154 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010155
10156 // Allocate and initialize a JSObject with all the content of theis function
10157 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010158 Handle<JSObject> closure_scope =
10159 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010160
10161 // Check whether the arguments shadow object exists.
10162 int arguments_shadow_index =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010163 shared->scope_info()->ContextSlotIndex(
10164 isolate->heap()->arguments_shadow_symbol(), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010165 if (arguments_shadow_index >= 0) {
10166 // In this case all the arguments are available in the arguments shadow
10167 // object.
10168 Handle<JSObject> arguments_shadow(
10169 JSObject::cast(context->get(arguments_shadow_index)));
10170 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010171 // We don't expect exception-throwing getters on the arguments shadow.
10172 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010173 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010174 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010175 SetProperty(closure_scope,
10176 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010177 Handle<Object>(element, isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010178 NONE,
10179 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010180 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010181 }
10182 }
10183
10184 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010185 if (!CopyContextLocalsToScopeObject(isolate,
10186 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010187 context, closure_scope)) {
10188 return Handle<JSObject>();
10189 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010190
10191 // Finally copy any properties from the function context extension. This will
10192 // be variables introduced by eval.
10193 if (context->has_extension()) {
10194 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010195 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010196 for (int i = 0; i < keys->length(); i++) {
10197 // Names of variables introduced by eval are strings.
10198 ASSERT(keys->get(i)->IsString());
10199 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010200 RETURN_IF_EMPTY_HANDLE_VALUE(
10201 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010202 SetProperty(closure_scope,
10203 key,
10204 GetProperty(ext, key),
10205 NONE,
10206 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010207 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010208 }
10209 }
10210
10211 return closure_scope;
10212}
10213
10214
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010215// Create a plain JSObject which materializes the scope for the specified
10216// catch context.
10217static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10218 Handle<Context> context) {
10219 ASSERT(context->IsCatchContext());
10220 Handle<String> name(String::cast(context->extension()));
10221 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10222 Handle<JSObject> catch_scope =
10223 isolate->factory()->NewJSObject(isolate->object_function());
10224 RETURN_IF_EMPTY_HANDLE_VALUE(
10225 isolate,
10226 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10227 Handle<JSObject>());
10228 return catch_scope;
10229}
10230
10231
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010232// Iterate over the actual scopes visible from a stack frame. All scopes are
10233// backed by an actual context except the local scope, which is inserted
10234// "artifically" in the context chain.
10235class ScopeIterator {
10236 public:
10237 enum ScopeType {
10238 ScopeTypeGlobal = 0,
10239 ScopeTypeLocal,
10240 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010241 ScopeTypeClosure,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010242 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010243 };
10244
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010245 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
10246 : isolate_(isolate),
10247 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010248 function_(JSFunction::cast(frame->function())),
10249 context_(Context::cast(frame->context())),
10250 local_done_(false),
10251 at_local_(false) {
10252
10253 // Check whether the first scope is actually a local scope.
10254 if (context_->IsGlobalContext()) {
10255 // If there is a stack slot for .result then this local scope has been
10256 // created for evaluating top level code and it is not a real local scope.
10257 // Checking for the existence of .result seems fragile, but the scope info
10258 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010259 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010260 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010261 at_local_ = index < 0;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010262 } else if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010263 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010264 } else if (context_->closure() != *function_) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010265 // The context_ is a with or catch block from the outer function.
10266 ASSERT(context_->IsWithContext() || context_->IsCatchContext());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010267 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010268 }
10269 }
10270
10271 // More scopes?
10272 bool Done() { return context_.is_null(); }
10273
10274 // Move to the next scope.
10275 void Next() {
10276 // If at a local scope mark the local scope as passed.
10277 if (at_local_) {
10278 at_local_ = false;
10279 local_done_ = true;
10280
10281 // If the current context is not associated with the local scope the
10282 // current context is the next real scope, so don't move to the next
10283 // context in this case.
10284 if (context_->closure() != *function_) {
10285 return;
10286 }
10287 }
10288
10289 // The global scope is always the last in the chain.
10290 if (context_->IsGlobalContext()) {
10291 context_ = Handle<Context>();
10292 return;
10293 }
10294
10295 // Move to the next context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010296 context_ = Handle<Context>(context_->previous(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010297
10298 // If passing the local scope indicate that the current scope is now the
10299 // local scope.
10300 if (!local_done_ &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010301 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010302 at_local_ = true;
10303 }
10304 }
10305
10306 // Return the type of the current scope.
10307 int Type() {
10308 if (at_local_) {
10309 return ScopeTypeLocal;
10310 }
10311 if (context_->IsGlobalContext()) {
10312 ASSERT(context_->global()->IsGlobalObject());
10313 return ScopeTypeGlobal;
10314 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010315 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010316 return ScopeTypeClosure;
10317 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010318 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010319 return ScopeTypeCatch;
10320 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010321 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010322 return ScopeTypeWith;
10323 }
10324
10325 // Return the JavaScript object with the content of the current scope.
10326 Handle<JSObject> ScopeObject() {
10327 switch (Type()) {
10328 case ScopeIterator::ScopeTypeGlobal:
10329 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010330 case ScopeIterator::ScopeTypeLocal:
10331 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010332 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010333 case ScopeIterator::ScopeTypeWith:
10334 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010335 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
10336 case ScopeIterator::ScopeTypeCatch:
10337 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010338 case ScopeIterator::ScopeTypeClosure:
10339 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010340 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010341 }
10342 UNREACHABLE();
10343 return Handle<JSObject>();
10344 }
10345
10346 // Return the context for this scope. For the local context there might not
10347 // be an actual context.
10348 Handle<Context> CurrentContext() {
10349 if (at_local_ && context_->closure() != *function_) {
10350 return Handle<Context>();
10351 }
10352 return context_;
10353 }
10354
10355#ifdef DEBUG
10356 // Debug print of the content of the current scope.
10357 void DebugPrint() {
10358 switch (Type()) {
10359 case ScopeIterator::ScopeTypeGlobal:
10360 PrintF("Global:\n");
10361 CurrentContext()->Print();
10362 break;
10363
10364 case ScopeIterator::ScopeTypeLocal: {
10365 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010366 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010367 scope_info.Print();
10368 if (!CurrentContext().is_null()) {
10369 CurrentContext()->Print();
10370 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010371 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010372 if (extension->IsJSContextExtensionObject()) {
10373 extension->Print();
10374 }
10375 }
10376 }
10377 break;
10378 }
10379
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010380 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010381 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010382 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010383 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010384
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010385 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010386 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010387 CurrentContext()->extension()->Print();
10388 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010389 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010390
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010391 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010392 PrintF("Closure:\n");
10393 CurrentContext()->Print();
10394 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010395 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010396 if (extension->IsJSContextExtensionObject()) {
10397 extension->Print();
10398 }
10399 }
10400 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010401
10402 default:
10403 UNREACHABLE();
10404 }
10405 PrintF("\n");
10406 }
10407#endif
10408
10409 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010410 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010411 JavaScriptFrame* frame_;
10412 Handle<JSFunction> function_;
10413 Handle<Context> context_;
10414 bool local_done_;
10415 bool at_local_;
10416
10417 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10418};
10419
10420
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010421RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010422 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010423 ASSERT(args.length() == 2);
10424
10425 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010426 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010427 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10428 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010429 if (!maybe_check->ToObject(&check)) return maybe_check;
10430 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010431 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10432
10433 // Get the frame where the debugging is performed.
10434 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010435 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010436 JavaScriptFrame* frame = it.frame();
10437
10438 // Count the visible scopes.
10439 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010440 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010441 n++;
10442 }
10443
10444 return Smi::FromInt(n);
10445}
10446
10447
10448static const int kScopeDetailsTypeIndex = 0;
10449static const int kScopeDetailsObjectIndex = 1;
10450static const int kScopeDetailsSize = 2;
10451
10452// Return an array with scope details
10453// args[0]: number: break id
10454// args[1]: number: frame index
10455// args[2]: number: scope index
10456//
10457// The array returned contains the following information:
10458// 0: Scope type
10459// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010460RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010461 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010462 ASSERT(args.length() == 3);
10463
10464 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010465 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010466 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10467 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010468 if (!maybe_check->ToObject(&check)) return maybe_check;
10469 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010470 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10471 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10472
10473 // Get the frame where the debugging is performed.
10474 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010475 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010476 JavaScriptFrame* frame = frame_it.frame();
10477
10478 // Find the requested scope.
10479 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010480 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010481 for (; !it.Done() && n < index; it.Next()) {
10482 n++;
10483 }
10484 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010485 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010486 }
10487
10488 // Calculate the size of the result.
10489 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010490 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010491
10492 // Fill in scope details.
10493 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010494 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010495 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010496 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010497
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010498 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010499}
10500
10501
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010502RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010503 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010504 ASSERT(args.length() == 0);
10505
10506#ifdef DEBUG
10507 // Print the scopes for the top frame.
10508 StackFrameLocator locator;
10509 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010510 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010511 it.DebugPrint();
10512 }
10513#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010514 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010515}
10516
10517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010518RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010519 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010520 ASSERT(args.length() == 1);
10521
10522 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010523 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010524 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10525 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010526 if (!maybe_result->ToObject(&result)) return maybe_result;
10527 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010528
10529 // Count all archived V8 threads.
10530 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010531 for (ThreadState* thread =
10532 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010533 thread != NULL;
10534 thread = thread->Next()) {
10535 n++;
10536 }
10537
10538 // Total number of threads is current thread and archived threads.
10539 return Smi::FromInt(n + 1);
10540}
10541
10542
10543static const int kThreadDetailsCurrentThreadIndex = 0;
10544static const int kThreadDetailsThreadIdIndex = 1;
10545static const int kThreadDetailsSize = 2;
10546
10547// Return an array with thread details
10548// args[0]: number: break id
10549// args[1]: number: thread index
10550//
10551// The array returned contains the following information:
10552// 0: Is current thread?
10553// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010554RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010555 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010556 ASSERT(args.length() == 2);
10557
10558 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010559 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010560 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10561 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010562 if (!maybe_check->ToObject(&check)) return maybe_check;
10563 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010564 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10565
10566 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010567 Handle<FixedArray> details =
10568 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010569
10570 // Thread index 0 is current thread.
10571 if (index == 0) {
10572 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010573 details->set(kThreadDetailsCurrentThreadIndex,
10574 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010575 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010576 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010577 } else {
10578 // Find the thread with the requested index.
10579 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010580 ThreadState* thread =
10581 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010582 while (index != n && thread != NULL) {
10583 thread = thread->Next();
10584 n++;
10585 }
10586 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010587 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010588 }
10589
10590 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010591 details->set(kThreadDetailsCurrentThreadIndex,
10592 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010593 details->set(kThreadDetailsThreadIdIndex,
10594 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010595 }
10596
10597 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010598 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010599}
10600
10601
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010602// Sets the disable break state
10603// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010604RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010605 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010606 ASSERT(args.length() == 1);
10607 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010608 isolate->debug()->set_disable_break(disable_break);
10609 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010610}
10611
10612
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010613RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010614 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010615 ASSERT(args.length() == 1);
10616
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010617 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10618 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010619 // Find the number of break points
10620 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010621 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010622 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010623 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010624 Handle<FixedArray>::cast(break_locations));
10625}
10626
10627
10628// Set a break point in a function
10629// args[0]: function
10630// args[1]: number: break source position (within the function source)
10631// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010632RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010633 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010634 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010635 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10636 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010637 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10638 RUNTIME_ASSERT(source_position >= 0);
10639 Handle<Object> break_point_object_arg = args.at<Object>(2);
10640
10641 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010642 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10643 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010644
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010645 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010646}
10647
10648
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010649Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10650 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010651 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010652 // Iterate the heap looking for SharedFunctionInfo generated from the
10653 // script. The inner most SharedFunctionInfo containing the source position
10654 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010655 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010656 // which is found is not compiled it is compiled and the heap is iterated
10657 // again as the compilation might create inner functions from the newly
10658 // compiled function and the actual requested break point might be in one of
10659 // these functions.
10660 bool done = false;
10661 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010662 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010663 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010664 while (!done) {
10665 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010666 for (HeapObject* obj = iterator.next();
10667 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010668 if (obj->IsSharedFunctionInfo()) {
10669 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10670 if (shared->script() == *script) {
10671 // If the SharedFunctionInfo found has the requested script data and
10672 // contains the source position it is a candidate.
10673 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010674 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010675 start_position = shared->start_position();
10676 }
10677 if (start_position <= position &&
10678 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010679 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010680 // candidate this is the new candidate.
10681 if (target.is_null()) {
10682 target_start_position = start_position;
10683 target = shared;
10684 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010685 if (target_start_position == start_position &&
10686 shared->end_position() == target->end_position()) {
10687 // If a top-level function contain only one function
10688 // declartion the source for the top-level and the function is
10689 // the same. In that case prefer the non top-level function.
10690 if (!shared->is_toplevel()) {
10691 target_start_position = start_position;
10692 target = shared;
10693 }
10694 } else if (target_start_position <= start_position &&
10695 shared->end_position() <= target->end_position()) {
10696 // This containment check includes equality as a function inside
10697 // a top-level function can share either start or end position
10698 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010699 target_start_position = start_position;
10700 target = shared;
10701 }
10702 }
10703 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010704 }
10705 }
10706 }
10707
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010708 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010709 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010710 }
10711
10712 // If the candidate found is compiled we are done. NOTE: when lazy
10713 // compilation of inner functions is introduced some additional checking
10714 // needs to be done here to compile inner functions.
10715 done = target->is_compiled();
10716 if (!done) {
10717 // If the candidate is not compiled compile it to reveal any inner
10718 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010719 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010720 }
10721 }
10722
10723 return *target;
10724}
10725
10726
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010727// Changes the state of a break point in a script and returns source position
10728// where break point was set. NOTE: Regarding performance see the NOTE for
10729// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010730// args[0]: script to set break point in
10731// args[1]: number: break source position (within the script source)
10732// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010733RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010734 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010735 ASSERT(args.length() == 3);
10736 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10737 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10738 RUNTIME_ASSERT(source_position >= 0);
10739 Handle<Object> break_point_object_arg = args.at<Object>(2);
10740
10741 // Get the script from the script wrapper.
10742 RUNTIME_ASSERT(wrapper->value()->IsScript());
10743 Handle<Script> script(Script::cast(wrapper->value()));
10744
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010745 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010746 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010747 if (!result->IsUndefined()) {
10748 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10749 // Find position within function. The script position might be before the
10750 // source position of the first function.
10751 int position;
10752 if (shared->start_position() > source_position) {
10753 position = 0;
10754 } else {
10755 position = source_position - shared->start_position();
10756 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010757 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010758 position += shared->start_position();
10759 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010760 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010761 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010762}
10763
10764
10765// Clear a break point
10766// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010767RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010768 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010769 ASSERT(args.length() == 1);
10770 Handle<Object> break_point_object_arg = args.at<Object>(0);
10771
10772 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010773 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010774
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010775 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010776}
10777
10778
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010779// Change the state of break on exceptions.
10780// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10781// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010782RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010783 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010784 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010785 RUNTIME_ASSERT(args[0]->IsNumber());
10786 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010787
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010788 // If the number doesn't match an enum value, the ChangeBreakOnException
10789 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010790 ExceptionBreakType type =
10791 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010792 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010793 isolate->debug()->ChangeBreakOnException(type, enable);
10794 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010795}
10796
10797
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010798// Returns the state of break on exceptions
10799// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010800RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010801 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010802 ASSERT(args.length() == 1);
10803 RUNTIME_ASSERT(args[0]->IsNumber());
10804
10805 ExceptionBreakType type =
10806 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010807 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010808 return Smi::FromInt(result);
10809}
10810
10811
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010812// Prepare for stepping
10813// args[0]: break id for checking execution state
10814// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010815// args[2]: number of times to perform the step, for step out it is the number
10816// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010817RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010818 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010819 ASSERT(args.length() == 3);
10820 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010821 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010822 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10823 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010824 if (!maybe_check->ToObject(&check)) return maybe_check;
10825 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010826 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010827 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010828 }
10829
10830 // Get the step action and check validity.
10831 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10832 if (step_action != StepIn &&
10833 step_action != StepNext &&
10834 step_action != StepOut &&
10835 step_action != StepInMin &&
10836 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010837 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010838 }
10839
10840 // Get the number of steps.
10841 int step_count = NumberToInt32(args[2]);
10842 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010843 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010844 }
10845
ager@chromium.orga1645e22009-09-09 19:27:10 +000010846 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010847 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010848
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010849 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010850 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
10851 step_count);
10852 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010853}
10854
10855
10856// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010857RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010858 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010859 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010860 isolate->debug()->ClearStepping();
10861 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010862}
10863
10864
10865// Creates a copy of the with context chain. The copy of the context chain is
10866// is linked to the function context supplied.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010867static Handle<Context> CopyWithContextChain(Isolate* isolate,
10868 Handle<Context> current,
10869 Handle<Context> base) {
10870 // At the end of the chain. Return the base context to link to.
10871 if (current->IsFunctionContext() || current->IsGlobalContext()) {
10872 return base;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010873 }
10874
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010875 // Recursively copy the with and catch contexts.
10876 HandleScope scope(isolate);
10877 Handle<Context> previous(current->previous());
10878 Handle<Context> new_previous = CopyWithContextChain(isolate, previous, base);
10879 Handle<Context> new_current;
10880 if (current->IsCatchContext()) {
10881 Handle<String> name(String::cast(current->extension()));
10882 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
10883 new_current =
10884 isolate->factory()->NewCatchContext(new_previous, name, thrown_object);
10885 } else {
10886 Handle<JSObject> extension(JSObject::cast(current->extension()));
10887 new_current =
10888 isolate->factory()->NewWithContext(new_previous, extension);
10889 }
10890 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010891}
10892
10893
10894// Helper function to find or create the arguments object for
10895// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010896static Handle<Object> GetArgumentsObject(Isolate* isolate,
10897 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010898 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010899 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010900 const ScopeInfo<>* sinfo,
10901 Handle<Context> function_context) {
10902 // Try to find the value of 'arguments' to pass as parameter. If it is not
10903 // found (that is the debugged function does not reference 'arguments' and
10904 // does not support eval) then create an 'arguments' object.
10905 int index;
10906 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010907 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010908 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010909 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010910 }
10911 }
10912
10913 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010914 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
10915 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010916 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010917 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010918 }
10919 }
10920
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010921 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010922 Handle<JSObject> arguments =
10923 isolate->factory()->NewArgumentsObject(function, length);
10924 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010925
10926 AssertNoAllocation no_gc;
10927 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010928 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010929 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010930 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010931 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010932 return arguments;
10933}
10934
10935
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010936static const char kSourceStr[] =
10937 "(function(arguments,__source__){return eval(__source__);})";
10938
10939
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010940// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010941// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010942// extension part has all the parameters and locals of the function on the
10943// stack frame. A function which calls eval with the code to evaluate is then
10944// compiled in this context and called in this context. As this context
10945// replaces the context of the function on the stack frame a new (empty)
10946// function is created as well to be used as the closure for the context.
10947// This function and the context acts as replacements for the function on the
10948// stack frame presenting the same view of the values of parameters and
10949// local variables as if the piece of JavaScript was evaluated at the point
10950// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010951RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010952 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010953
10954 // Check the execution state and decode arguments frame and source to be
10955 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010956 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010957 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010958 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10959 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010960 if (!maybe_check_result->ToObject(&check_result)) {
10961 return maybe_check_result;
10962 }
10963 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010964 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10965 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010966 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010967 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010968
10969 // Handle the processing of break.
10970 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010971
10972 // Get the frame where the debugging is performed.
10973 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010974 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010975 JavaScriptFrame* frame = it.frame();
10976 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010977 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010978 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010979
10980 // Traverse the saved contexts chain to find the active context for the
10981 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010982 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010983 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010984 save = save->prev();
10985 }
10986 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010987 SaveContext savex(isolate);
10988 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010989
10990 // Create the (empty) function replacing the function on the stack frame for
10991 // the purpose of evaluating in the context created below. It is important
10992 // that this function does not describe any parameters and local variables
10993 // in the context. If it does then this will cause problems with the lookup
10994 // in Context::Lookup, where context slots for parameters and local variables
10995 // are looked at before the extension object.
10996 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010997 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
10998 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010999 go_between->set_context(function->context());
11000#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011001 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011002 ASSERT(go_between_sinfo.number_of_parameters() == 0);
11003 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
11004#endif
11005
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011006 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011007 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
11008 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011009
11010 // Allocate a new context for the debug evaluation and set the extension
11011 // object build.
11012 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011013 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11014 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011015 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011016 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011017 Handle<Context> frame_context(Context::cast(frame->context()));
11018 Handle<Context> function_context(frame_context->fcontext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011019 context = CopyWithContextChain(isolate, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011020
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011021 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011022 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
11023 context = isolate->factory()->NewWithContext(context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011024 }
11025
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011026 // Wrap the evaluation statement in a new function compiled in the newly
11027 // created context. The function has one parameter which has to be called
11028 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011029 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011030 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011031
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011032 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011033 isolate->factory()->NewStringFromAscii(
11034 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011035
11036 // Currently, the eval code will be executed in non-strict mode,
11037 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011038 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011039 Compiler::CompileEval(function_source,
11040 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011041 context->IsGlobalContext(),
11042 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011043 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011044 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011045 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011046
11047 // Invoke the result of the compilation to get the evaluation function.
11048 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011049 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011050 Handle<Object> evaluation_function =
11051 Execution::Call(compiled_function, receiver, 0, NULL,
11052 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011053 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011054
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011055 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
11056 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011057 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011058
11059 // Invoke the evaluation function and return the result.
11060 const int argc = 2;
11061 Object** argv[argc] = { arguments.location(),
11062 Handle<Object>::cast(source).location() };
11063 Handle<Object> result =
11064 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11065 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011066 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011067
11068 // Skip the global proxy as it has no properties and always delegates to the
11069 // real global object.
11070 if (result->IsJSGlobalProxy()) {
11071 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11072 }
11073
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011074 return *result;
11075}
11076
11077
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011078RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011079 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011080
11081 // Check the execution state and decode arguments frame and source to be
11082 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011083 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011084 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011085 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11086 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011087 if (!maybe_check_result->ToObject(&check_result)) {
11088 return maybe_check_result;
11089 }
11090 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011091 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011092 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011093 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011094
11095 // Handle the processing of break.
11096 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011097
11098 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011099 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011100 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011101 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011102 top = top->prev();
11103 }
11104 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011105 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011106 }
11107
11108 // Get the global context now set to the top context from before the
11109 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011110 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011111
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011112 bool is_global = true;
11113
11114 if (additional_context->IsJSObject()) {
11115 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011116 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11117 isolate->factory()->empty_string(),
11118 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011119 go_between->set_context(*context);
11120 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011121 isolate->factory()->NewFunctionContext(
11122 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011123 context->set_extension(JSObject::cast(*additional_context));
11124 is_global = false;
11125 }
11126
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011127 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011128 // Currently, the eval code will be executed in non-strict mode,
11129 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011130 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011131 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011132 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011133 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011134 Handle<JSFunction>(
11135 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11136 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011137
11138 // Invoke the result of the compilation to get the evaluation function.
11139 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011140 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011141 Handle<Object> result =
11142 Execution::Call(compiled_function, receiver, 0, NULL,
11143 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011144 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011145 return *result;
11146}
11147
11148
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011149RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011150 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011151 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011152
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011153 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011154 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011155
11156 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011157 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011158 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11159 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11160 // because using
11161 // instances->set(i, *GetScriptWrapper(script))
11162 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11163 // already have deferenced the instances handle.
11164 Handle<JSValue> wrapper = GetScriptWrapper(script);
11165 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011166 }
11167
11168 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011169 Handle<JSObject> result =
11170 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011171 Handle<JSArray>::cast(result)->SetContent(*instances);
11172 return *result;
11173}
11174
11175
11176// Helper function used by Runtime_DebugReferencedBy below.
11177static int DebugReferencedBy(JSObject* target,
11178 Object* instance_filter, int max_references,
11179 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011180 JSFunction* arguments_function) {
11181 NoHandleAllocation ha;
11182 AssertNoAllocation no_alloc;
11183
11184 // Iterate the heap.
11185 int count = 0;
11186 JSObject* last = NULL;
11187 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011188 HeapObject* heap_obj = NULL;
11189 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011190 (max_references == 0 || count < max_references)) {
11191 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011192 if (heap_obj->IsJSObject()) {
11193 // Skip context extension objects and argument arrays as these are
11194 // checked in the context of functions using them.
11195 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011196 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011197 obj->map()->constructor() == arguments_function) {
11198 continue;
11199 }
11200
11201 // Check if the JS object has a reference to the object looked for.
11202 if (obj->ReferencesObject(target)) {
11203 // Check instance filter if supplied. This is normally used to avoid
11204 // references from mirror objects (see Runtime_IsInPrototypeChain).
11205 if (!instance_filter->IsUndefined()) {
11206 Object* V = obj;
11207 while (true) {
11208 Object* prototype = V->GetPrototype();
11209 if (prototype->IsNull()) {
11210 break;
11211 }
11212 if (instance_filter == prototype) {
11213 obj = NULL; // Don't add this object.
11214 break;
11215 }
11216 V = prototype;
11217 }
11218 }
11219
11220 if (obj != NULL) {
11221 // Valid reference found add to instance array if supplied an update
11222 // count.
11223 if (instances != NULL && count < instances_size) {
11224 instances->set(count, obj);
11225 }
11226 last = obj;
11227 count++;
11228 }
11229 }
11230 }
11231 }
11232
11233 // Check for circular reference only. This can happen when the object is only
11234 // referenced from mirrors and has a circular reference in which case the
11235 // object is not really alive and would have been garbage collected if not
11236 // referenced from the mirror.
11237 if (count == 1 && last == target) {
11238 count = 0;
11239 }
11240
11241 // Return the number of referencing objects found.
11242 return count;
11243}
11244
11245
11246// Scan the heap for objects with direct references to an object
11247// args[0]: the object to find references to
11248// args[1]: constructor function for instances to exclude (Mirror)
11249// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011250RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011251 ASSERT(args.length() == 3);
11252
11253 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011254 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011255
11256 // Check parameters.
11257 CONVERT_CHECKED(JSObject, target, args[0]);
11258 Object* instance_filter = args[1];
11259 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11260 instance_filter->IsJSObject());
11261 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11262 RUNTIME_ASSERT(max_references >= 0);
11263
11264 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011265 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011266 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011267 JSFunction* arguments_function =
11268 JSFunction::cast(arguments_boilerplate->map()->constructor());
11269
11270 // Get the number of referencing objects.
11271 int count;
11272 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011273 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011274
11275 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011276 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011277 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011278 if (!maybe_object->ToObject(&object)) return maybe_object;
11279 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011280 FixedArray* instances = FixedArray::cast(object);
11281
11282 // Fill the referencing objects.
11283 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011284 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011285
11286 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011287 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011288 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11289 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011290 if (!maybe_result->ToObject(&result)) return maybe_result;
11291 }
11292 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011293 return result;
11294}
11295
11296
11297// Helper function used by Runtime_DebugConstructedBy below.
11298static int DebugConstructedBy(JSFunction* constructor, int max_references,
11299 FixedArray* instances, int instances_size) {
11300 AssertNoAllocation no_alloc;
11301
11302 // Iterate the heap.
11303 int count = 0;
11304 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011305 HeapObject* heap_obj = NULL;
11306 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011307 (max_references == 0 || count < max_references)) {
11308 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011309 if (heap_obj->IsJSObject()) {
11310 JSObject* obj = JSObject::cast(heap_obj);
11311 if (obj->map()->constructor() == constructor) {
11312 // Valid reference found add to instance array if supplied an update
11313 // count.
11314 if (instances != NULL && count < instances_size) {
11315 instances->set(count, obj);
11316 }
11317 count++;
11318 }
11319 }
11320 }
11321
11322 // Return the number of referencing objects found.
11323 return count;
11324}
11325
11326
11327// Scan the heap for objects constructed by a specific function.
11328// args[0]: the constructor to find instances of
11329// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011330RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011331 ASSERT(args.length() == 2);
11332
11333 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011334 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011335
11336 // Check parameters.
11337 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11338 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11339 RUNTIME_ASSERT(max_references >= 0);
11340
11341 // Get the number of referencing objects.
11342 int count;
11343 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11344
11345 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011346 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011347 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011348 if (!maybe_object->ToObject(&object)) return maybe_object;
11349 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011350 FixedArray* instances = FixedArray::cast(object);
11351
11352 // Fill the referencing objects.
11353 count = DebugConstructedBy(constructor, max_references, instances, count);
11354
11355 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011356 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011357 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11358 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011359 if (!maybe_result->ToObject(&result)) return maybe_result;
11360 }
11361 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011362 return result;
11363}
11364
11365
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011366// Find the effective prototype object as returned by __proto__.
11367// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011368RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011369 ASSERT(args.length() == 1);
11370
11371 CONVERT_CHECKED(JSObject, obj, args[0]);
11372
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011373 // Use the __proto__ accessor.
11374 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011375}
11376
11377
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011378RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011379 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011380 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011381 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011382}
11383
11384
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011385RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011386#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011387 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011388 ASSERT(args.length() == 1);
11389 // Get the function and make sure it is compiled.
11390 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011391 Handle<SharedFunctionInfo> shared(func->shared());
11392 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011393 return Failure::Exception();
11394 }
11395 func->code()->PrintLn();
11396#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011397 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011398}
ager@chromium.org9085a012009-05-11 19:22:57 +000011399
11400
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011401RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011402#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011403 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011404 ASSERT(args.length() == 1);
11405 // Get the function and make sure it is compiled.
11406 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011407 Handle<SharedFunctionInfo> shared(func->shared());
11408 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011409 return Failure::Exception();
11410 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011411 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011412#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011413 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011414}
11415
11416
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011417RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011418 NoHandleAllocation ha;
11419 ASSERT(args.length() == 1);
11420
11421 CONVERT_CHECKED(JSFunction, f, args[0]);
11422 return f->shared()->inferred_name();
11423}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011424
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011425
11426static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011427 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011428 AssertNoAllocation no_allocations;
11429
11430 int counter = 0;
11431 int buffer_size = buffer->length();
11432 HeapIterator iterator;
11433 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11434 ASSERT(obj != NULL);
11435 if (!obj->IsSharedFunctionInfo()) {
11436 continue;
11437 }
11438 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11439 if (shared->script() != script) {
11440 continue;
11441 }
11442 if (counter < buffer_size) {
11443 buffer->set(counter, shared);
11444 }
11445 counter++;
11446 }
11447 return counter;
11448}
11449
11450// For a script finds all SharedFunctionInfo's in the heap that points
11451// to this script. Returns JSArray of SharedFunctionInfo wrapped
11452// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011453RUNTIME_FUNCTION(MaybeObject*,
11454 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011455 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011456 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011457 CONVERT_CHECKED(JSValue, script_value, args[0]);
11458
11459 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11460
11461 const int kBufferSize = 32;
11462
11463 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011464 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011465 int number = FindSharedFunctionInfosForScript(*script, *array);
11466 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011467 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011468 FindSharedFunctionInfosForScript(*script, *array);
11469 }
11470
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011471 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011472 result->set_length(Smi::FromInt(number));
11473
11474 LiveEdit::WrapSharedFunctionInfos(result);
11475
11476 return *result;
11477}
11478
11479// For a script calculates compilation information about all its functions.
11480// The script source is explicitly specified by the second argument.
11481// The source of the actual script is not used, however it is important that
11482// all generated code keeps references to this particular instance of script.
11483// Returns a JSArray of compilation infos. The array is ordered so that
11484// each function with all its descendant is always stored in a continues range
11485// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011486RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011487 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011488 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011489 CONVERT_CHECKED(JSValue, script, args[0]);
11490 CONVERT_ARG_CHECKED(String, source, 1);
11491 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11492
11493 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11494
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011495 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011496 return Failure::Exception();
11497 }
11498
11499 return result;
11500}
11501
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011502// Changes the source of the script to a new_source.
11503// If old_script_name is provided (i.e. is a String), also creates a copy of
11504// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011505RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011506 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011507 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011508 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11509 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011510 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011511
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011512 CONVERT_CHECKED(Script, original_script_pointer,
11513 original_script_value->value());
11514 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011515
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011516 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11517 new_source,
11518 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011519
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011520 if (old_script->IsScript()) {
11521 Handle<Script> script_handle(Script::cast(old_script));
11522 return *(GetScriptWrapper(script_handle));
11523 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011524 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011525 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011526}
11527
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011528
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011529RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011530 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011531 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011532 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11533 return LiveEdit::FunctionSourceUpdated(shared_info);
11534}
11535
11536
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011537// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011538RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011539 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011540 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011541 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11542 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11543
ager@chromium.orgac091b72010-05-05 07:34:42 +000011544 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011545}
11546
11547// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011548RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011549 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011550 HandleScope scope(isolate);
11551 Handle<Object> function_object(args[0], isolate);
11552 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011553
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011554 if (function_object->IsJSValue()) {
11555 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11556 if (script_object->IsJSValue()) {
11557 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011558 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011559 }
11560
11561 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11562 } else {
11563 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11564 // and we check it in this function.
11565 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011566
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011567 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011568}
11569
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011570
11571// In a code of a parent function replaces original function as embedded object
11572// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011573RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011574 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011575 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011576
11577 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11578 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11579 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11580
11581 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11582 subst_wrapper);
11583
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011584 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011585}
11586
11587
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011588// Updates positions of a shared function info (first parameter) according
11589// to script source change. Text change is described in second parameter as
11590// array of groups of 3 numbers:
11591// (change_begin, change_end, change_end_new_position).
11592// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011593RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011594 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011595 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011596 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11597 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11598
ager@chromium.orgac091b72010-05-05 07:34:42 +000011599 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011600}
11601
11602
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011603// For array of SharedFunctionInfo's (each wrapped in JSValue)
11604// checks that none of them have activations on stacks (of any thread).
11605// Returns array of the same length with corresponding results of
11606// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011607RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011608 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011609 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011610 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011611 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011612
ager@chromium.org357bf652010-04-12 11:30:10 +000011613 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011614}
11615
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011616// Compares 2 strings line-by-line, then token-wise and returns diff in form
11617// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11618// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011619RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011620 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011621 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011622 CONVERT_ARG_CHECKED(String, s1, 0);
11623 CONVERT_ARG_CHECKED(String, s2, 1);
11624
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011625 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011626}
11627
11628
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011629// A testing entry. Returns statement position which is the closest to
11630// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011631RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011632 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011633 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011634 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11635 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11636
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011637 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011638
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011639 if (code->kind() != Code::FUNCTION &&
11640 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011641 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011642 }
11643
11644 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011645 int closest_pc = 0;
11646 int distance = kMaxInt;
11647 while (!it.done()) {
11648 int statement_position = static_cast<int>(it.rinfo()->data());
11649 // Check if this break point is closer that what was previously found.
11650 if (source_position <= statement_position &&
11651 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011652 closest_pc =
11653 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011654 distance = statement_position - source_position;
11655 // Check whether we can't get any closer.
11656 if (distance == 0) break;
11657 }
11658 it.next();
11659 }
11660
11661 return Smi::FromInt(closest_pc);
11662}
11663
11664
ager@chromium.org357bf652010-04-12 11:30:10 +000011665// Calls specified function with or without entering the debugger.
11666// This is used in unit tests to run code as if debugger is entered or simply
11667// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011668RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011669 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011670 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011671 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11672 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11673
11674 Handle<Object> result;
11675 bool pending_exception;
11676 {
11677 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011678 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011679 &pending_exception);
11680 } else {
11681 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011682 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011683 &pending_exception);
11684 }
11685 }
11686 if (!pending_exception) {
11687 return *result;
11688 } else {
11689 return Failure::Exception();
11690 }
11691}
11692
11693
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011694// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011695RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011696 CONVERT_CHECKED(String, arg, args[0]);
11697 SmartPointer<char> flags =
11698 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11699 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011700 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011701}
11702
11703
11704// Performs a GC.
11705// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011706RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011707 isolate->heap()->CollectAllGarbage(true);
11708 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011709}
11710
11711
11712// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011713RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011714 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011715 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011716 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011717 }
11718 return Smi::FromInt(usage);
11719}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011720
11721
11722// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011723RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011724#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011725 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011726#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011727 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011728#endif
11729}
11730
11731
11732// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011733RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011734#ifdef LIVE_OBJECT_LIST
11735 return LiveObjectList::Capture();
11736#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011737 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011738#endif
11739}
11740
11741
11742// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011743RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011744#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011745 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011746 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011747 return success ? isolate->heap()->true_value() :
11748 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011749#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011750 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011751#endif
11752}
11753
11754
11755// Generates the response to a debugger request for a dump of the objects
11756// contained in the difference between the captured live object lists
11757// specified by id1 and id2.
11758// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11759// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011760RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011761#ifdef LIVE_OBJECT_LIST
11762 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011763 CONVERT_SMI_ARG_CHECKED(id1, 0);
11764 CONVERT_SMI_ARG_CHECKED(id2, 1);
11765 CONVERT_SMI_ARG_CHECKED(start, 2);
11766 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011767 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11768 EnterDebugger enter_debugger;
11769 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11770#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011771 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011772#endif
11773}
11774
11775
11776// Gets the specified object as requested by the debugger.
11777// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011778RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011779#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011780 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011781 Object* result = LiveObjectList::GetObj(obj_id);
11782 return result;
11783#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011784 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011785#endif
11786}
11787
11788
11789// Gets the obj id for the specified address if valid.
11790// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011791RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011792#ifdef LIVE_OBJECT_LIST
11793 HandleScope scope;
11794 CONVERT_ARG_CHECKED(String, address, 0);
11795 Object* result = LiveObjectList::GetObjId(address);
11796 return result;
11797#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011798 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011799#endif
11800}
11801
11802
11803// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011804RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011805#ifdef LIVE_OBJECT_LIST
11806 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011807 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011808 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11809 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11810 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11811 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11812 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11813
11814 Handle<JSObject> instance_filter;
11815 if (args[1]->IsJSObject()) {
11816 instance_filter = args.at<JSObject>(1);
11817 }
11818 bool verbose = false;
11819 if (args[2]->IsBoolean()) {
11820 verbose = args[2]->IsTrue();
11821 }
11822 int start = 0;
11823 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011824 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011825 }
11826 int limit = Smi::kMaxValue;
11827 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011828 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011829 }
11830
11831 return LiveObjectList::GetObjRetainers(obj_id,
11832 instance_filter,
11833 verbose,
11834 start,
11835 limit,
11836 filter_obj);
11837#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011838 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011839#endif
11840}
11841
11842
11843// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011844RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011845#ifdef LIVE_OBJECT_LIST
11846 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011847 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
11848 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011849 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11850
11851 Handle<JSObject> instance_filter;
11852 if (args[2]->IsJSObject()) {
11853 instance_filter = args.at<JSObject>(2);
11854 }
11855
11856 Object* result =
11857 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11858 return result;
11859#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011860 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011861#endif
11862}
11863
11864
11865// Generates the response to a debugger request for a list of all
11866// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011867RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011868#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011869 CONVERT_SMI_ARG_CHECKED(start, 0);
11870 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011871 return LiveObjectList::Info(start, count);
11872#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011873 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011874#endif
11875}
11876
11877
11878// Gets a dump of the specified object as requested by the debugger.
11879// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011880RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011881#ifdef LIVE_OBJECT_LIST
11882 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011883 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011884 Object* result = LiveObjectList::PrintObj(obj_id);
11885 return result;
11886#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011887 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011888#endif
11889}
11890
11891
11892// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011893RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011894#ifdef LIVE_OBJECT_LIST
11895 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011896 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011897#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011898 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011899#endif
11900}
11901
11902
11903// Generates the response to a debugger request for a summary of the types
11904// of objects in the difference between the captured live object lists
11905// specified by id1 and id2.
11906// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11907// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011908RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011909#ifdef LIVE_OBJECT_LIST
11910 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011911 CONVERT_SMI_ARG_CHECKED(id1, 0);
11912 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011913 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11914
11915 EnterDebugger enter_debugger;
11916 return LiveObjectList::Summarize(id1, id2, filter_obj);
11917#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011918 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011919#endif
11920}
11921
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011922#endif // ENABLE_DEBUGGER_SUPPORT
11923
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011924
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011925#ifdef ENABLE_LOGGING_AND_PROFILING
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011926RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011927 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011928 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011929
11930 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011931 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11932 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011933 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011934}
11935
11936
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011937RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011938 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011939 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011940
11941 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011942 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11943 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011944 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011945}
11946
11947#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011948
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011949// Finds the script object from the script data. NOTE: This operation uses
11950// heap traversal to find the function generated for the source position
11951// for the requested break point. For lazily compiled functions several heap
11952// traversals might be required rendering this operation as a rather slow
11953// operation. However for setting break points which is normally done through
11954// some kind of user interaction the performance is not crucial.
11955static Handle<Object> Runtime_GetScriptFromScriptName(
11956 Handle<String> script_name) {
11957 // Scan the heap for Script objects to find the script with the requested
11958 // script data.
11959 Handle<Script> script;
11960 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011961 HeapObject* obj = NULL;
11962 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011963 // If a script is found check if it has the script data requested.
11964 if (obj->IsScript()) {
11965 if (Script::cast(obj)->name()->IsString()) {
11966 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11967 script = Handle<Script>(Script::cast(obj));
11968 }
11969 }
11970 }
11971 }
11972
11973 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011974 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011975
11976 // Return the script found.
11977 return GetScriptWrapper(script);
11978}
11979
11980
11981// Get the script object from script data. NOTE: Regarding performance
11982// see the NOTE for GetScriptFromScriptData.
11983// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011984RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011985 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011986
11987 ASSERT(args.length() == 1);
11988
11989 CONVERT_CHECKED(String, script_name, args[0]);
11990
11991 // Find the requested script.
11992 Handle<Object> result =
11993 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11994 return *result;
11995}
11996
11997
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011998// Determines whether the given stack frame should be displayed in
11999// a stack trace. The caller is the error constructor that asked
12000// for the stack trace to be collected. The first time a construct
12001// call to this function is encountered it is skipped. The seen_caller
12002// in/out parameter is used to remember if the caller has been seen
12003// yet.
12004static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
12005 bool* seen_caller) {
12006 // Only display JS frames.
12007 if (!raw_frame->is_java_script())
12008 return false;
12009 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12010 Object* raw_fun = frame->function();
12011 // Not sure when this can happen but skip it just in case.
12012 if (!raw_fun->IsJSFunction())
12013 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012014 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012015 *seen_caller = true;
12016 return false;
12017 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012018 // Skip all frames until we've seen the caller. Also, skip the most
12019 // obvious builtin calls. Some builtin calls (such as Number.ADD
12020 // which is invoked using 'call') are very difficult to recognize
12021 // so we're leaving them in for now.
12022 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012023}
12024
12025
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012026// Collect the raw data for a stack trace. Returns an array of 4
12027// element segments each containing a receiver, function, code and
12028// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012029RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012030 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012031 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012032 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12033
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012034 HandleScope scope(isolate);
12035 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012036
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012037 limit = Max(limit, 0); // Ensure that limit is not negative.
12038 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012039 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012040 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012041
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012042 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012043 // If the caller parameter is a function we skip frames until we're
12044 // under it before starting to collect.
12045 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012046 int cursor = 0;
12047 int frames_seen = 0;
12048 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012049 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012050 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012051 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012052 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012053 // Set initial size to the maximum inlining level + 1 for the outermost
12054 // function.
12055 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012056 frame->Summarize(&frames);
12057 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012058 if (cursor + 4 > elements->length()) {
12059 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12060 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012061 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012062 for (int i = 0; i < cursor; i++) {
12063 new_elements->set(i, elements->get(i));
12064 }
12065 elements = new_elements;
12066 }
12067 ASSERT(cursor + 4 <= elements->length());
12068
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012069 Handle<Object> recv = frames[i].receiver();
12070 Handle<JSFunction> fun = frames[i].function();
12071 Handle<Code> code = frames[i].code();
12072 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012073 elements->set(cursor++, *recv);
12074 elements->set(cursor++, *fun);
12075 elements->set(cursor++, *code);
12076 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012077 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012078 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012079 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012080 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012081 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012082 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012083 return *result;
12084}
12085
12086
ager@chromium.org3811b432009-10-28 14:53:37 +000012087// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012088RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012089 ASSERT_EQ(args.length(), 0);
12090
12091 NoHandleAllocation ha;
12092
12093 const char* version_string = v8::V8::GetVersion();
12094
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012095 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12096 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012097}
12098
12099
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012100RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012101 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012102 OS::PrintError("abort: %s\n",
12103 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012104 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012105 OS::Abort();
12106 UNREACHABLE();
12107 return NULL;
12108}
12109
12110
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012111RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012112 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012113 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012114 Object* key = args[1];
12115
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012116 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012117 Object* o = cache->get(finger_index);
12118 if (o == key) {
12119 // The fastest case: hit the same place again.
12120 return cache->get(finger_index + 1);
12121 }
12122
12123 for (int i = finger_index - 2;
12124 i >= JSFunctionResultCache::kEntriesIndex;
12125 i -= 2) {
12126 o = cache->get(i);
12127 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012128 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012129 return cache->get(i + 1);
12130 }
12131 }
12132
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012133 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012134 ASSERT(size <= cache->length());
12135
12136 for (int i = size - 2; i > finger_index; i -= 2) {
12137 o = cache->get(i);
12138 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012139 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012140 return cache->get(i + 1);
12141 }
12142 }
12143
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012144 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012145 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012146
12147 Handle<JSFunctionResultCache> cache_handle(cache);
12148 Handle<Object> key_handle(key);
12149 Handle<Object> value;
12150 {
12151 Handle<JSFunction> factory(JSFunction::cast(
12152 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12153 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012154 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012155 // This handle is nor shared, nor used later, so it's safe.
12156 Object** argv[] = { key_handle.location() };
12157 bool pending_exception = false;
12158 value = Execution::Call(factory,
12159 receiver,
12160 1,
12161 argv,
12162 &pending_exception);
12163 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012164 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012165
12166#ifdef DEBUG
12167 cache_handle->JSFunctionResultCacheVerify();
12168#endif
12169
12170 // Function invocation may have cleared the cache. Reread all the data.
12171 finger_index = cache_handle->finger_index();
12172 size = cache_handle->size();
12173
12174 // If we have spare room, put new data into it, otherwise evict post finger
12175 // entry which is likely to be the least recently used.
12176 int index = -1;
12177 if (size < cache_handle->length()) {
12178 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12179 index = size;
12180 } else {
12181 index = finger_index + JSFunctionResultCache::kEntrySize;
12182 if (index == cache_handle->length()) {
12183 index = JSFunctionResultCache::kEntriesIndex;
12184 }
12185 }
12186
12187 ASSERT(index % 2 == 0);
12188 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12189 ASSERT(index < cache_handle->length());
12190
12191 cache_handle->set(index, *key_handle);
12192 cache_handle->set(index + 1, *value);
12193 cache_handle->set_finger_index(index);
12194
12195#ifdef DEBUG
12196 cache_handle->JSFunctionResultCacheVerify();
12197#endif
12198
12199 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012200}
12201
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012202
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012203RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012204 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012205 CONVERT_ARG_CHECKED(String, type, 0);
12206 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012207 return *isolate->factory()->NewJSMessageObject(
12208 type,
12209 arguments,
12210 0,
12211 0,
12212 isolate->factory()->undefined_value(),
12213 isolate->factory()->undefined_value(),
12214 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012215}
12216
12217
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012218RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012219 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12220 return message->type();
12221}
12222
12223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012224RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012225 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12226 return message->arguments();
12227}
12228
12229
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012230RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012231 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12232 return Smi::FromInt(message->start_position());
12233}
12234
12235
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012236RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012237 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12238 return message->script();
12239}
12240
12241
kasper.lund44510672008-07-25 07:37:58 +000012242#ifdef DEBUG
12243// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12244// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012245RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012246 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012247 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012248#define COUNT_ENTRY(Name, argc, ressize) + 1
12249 int entry_count = 0
12250 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12251 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12252 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12253#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012254 Factory* factory = isolate->factory();
12255 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012256 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012257 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012258#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012259 { \
12260 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012261 Handle<String> name; \
12262 /* Inline runtime functions have an underscore in front of the name. */ \
12263 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012264 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012265 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12266 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012267 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012268 Vector<const char>(#Name, StrLength(#Name))); \
12269 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012270 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012271 pair_elements->set(0, *name); \
12272 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012273 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012274 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012275 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012276 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012277 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012278 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012279 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012280 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012281#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012282 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012283 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012284 return *result;
12285}
kasper.lund44510672008-07-25 07:37:58 +000012286#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012287
12288
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012289RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012290 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012291 CONVERT_CHECKED(String, format, args[0]);
12292 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012293 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012294 LOGGER->LogRuntime(chars, elms);
12295 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012296}
12297
12298
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012299RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012300 UNREACHABLE(); // implemented as macro in the parser
12301 return NULL;
12302}
12303
12304
12305// ----------------------------------------------------------------------------
12306// Implementation of Runtime
12307
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012308#define F(name, number_of_args, result_size) \
12309 { Runtime::k##name, Runtime::RUNTIME, #name, \
12310 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012311
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012312
12313#define I(name, number_of_args, result_size) \
12314 { Runtime::kInline##name, Runtime::INLINE, \
12315 "_" #name, NULL, number_of_args, result_size },
12316
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012317static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012318 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012319 INLINE_FUNCTION_LIST(I)
12320 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012321};
12322
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012323
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012324MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12325 Object* dictionary) {
12326 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012327 ASSERT(dictionary != NULL);
12328 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12329 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012330 Object* name_symbol;
12331 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012332 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012333 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12334 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012335 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012336 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12337 String::cast(name_symbol),
12338 Smi::FromInt(i),
12339 PropertyDetails(NONE, NORMAL));
12340 if (!maybe_dictionary->ToObject(&dictionary)) {
12341 // Non-recoverable failure. Calling code must restart heap
12342 // initialization.
12343 return maybe_dictionary;
12344 }
12345 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012346 }
12347 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012348}
12349
12350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012351const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12352 Heap* heap = name->GetHeap();
12353 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012354 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012355 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012356 int function_index = Smi::cast(smi_index)->value();
12357 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012358 }
12359 return NULL;
12360}
12361
12362
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012363const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012364 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12365}
12366
12367
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012368void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012369 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012370 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012371 if (failure->IsRetryAfterGC()) {
12372 // Try to do a garbage collection; ignore it if it fails. The C
12373 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012374 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012375 } else {
12376 // Handle last resort GC and make sure to allow future allocations
12377 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012378 isolate->counters()->gc_last_resort_from_js()->Increment();
12379 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012380 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012381}
12382
12383
12384} } // namespace v8::internal