blob: 7d9ec3c7ade020aee877192b08b7ea93a07a23c0 [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
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000084// Cast the given object to a Smi and store its value in an int variable
85// with the given name. If the object is not a Smi call IllegalOperation
86// and return.
87#define CONVERT_SMI_CHECKED(name, obj) \
88 RUNTIME_ASSERT(obj->IsSmi()); \
89 int name = Smi::cast(obj)->value();
90
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000091// Cast the given object to a double and store it in a variable with
92// the given name. If the object is not a number (as opposed to
93// the number not-a-number) call IllegalOperation and return.
94#define CONVERT_DOUBLE_CHECKED(name, obj) \
95 RUNTIME_ASSERT(obj->IsNumber()); \
96 double name = (obj)->Number();
97
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);
485 CONVERT_SMI_CHECKED(literals_index, args[1]);
486 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);
502 CONVERT_SMI_CHECKED(literals_index, args[1]);
503 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000504 CONVERT_SMI_CHECKED(flags, args[3]);
505 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);
528 CONVERT_SMI_CHECKED(literals_index, args[1]);
529 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000530 CONVERT_SMI_CHECKED(flags, args[3]);
531 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);
554 CONVERT_SMI_CHECKED(literals_index, args[1]);
555 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);
573 CONVERT_SMI_CHECKED(literals_index, args[1]);
574 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 =
597 (prototype->IsJSObject() || prototype->IsJSProxy()) ? prototype
598 : isolate->heap()->null_value();
599 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
600}
601
602
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000603RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCatchExtensionObject) {
ager@chromium.org32912102009-01-16 10:38:43 +0000604 ASSERT(args.length() == 2);
605 CONVERT_CHECKED(String, key, args[0]);
606 Object* value = args[1];
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000607 ASSERT(!value->IsFailure());
ager@chromium.org32912102009-01-16 10:38:43 +0000608 // Create a catch context extension object.
609 JSFunction* constructor =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000610 isolate->context()->global_context()->
611 context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000612 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000613 { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000614 if (!maybe_object->ToObject(&object)) return maybe_object;
615 }
ager@chromium.org32912102009-01-16 10:38:43 +0000616 // Assign the exception value to the catch variable and make sure
617 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000618 { MaybeObject* maybe_value =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000619 // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4.
620 JSObject::cast(object)->SetProperty(
621 key, value, DONT_DELETE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000622 if (!maybe_value->ToObject(&value)) return maybe_value;
623 }
ager@chromium.org32912102009-01-16 10:38:43 +0000624 return object;
625}
626
627
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000628RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000629 NoHandleAllocation ha;
630 ASSERT(args.length() == 1);
631 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000632 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000633 return JSObject::cast(obj)->class_name();
634}
635
ager@chromium.org7c537e22008-10-16 08:43:32 +0000636
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000637RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000638 NoHandleAllocation ha;
639 ASSERT(args.length() == 2);
640 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
641 Object* O = args[0];
642 Object* V = args[1];
643 while (true) {
644 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000645 if (prototype->IsNull()) return isolate->heap()->false_value();
646 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000647 V = prototype;
648 }
649}
650
651
ager@chromium.org9085a012009-05-11 19:22:57 +0000652// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000653RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000654 NoHandleAllocation ha;
655 ASSERT(args.length() == 2);
656 CONVERT_CHECKED(JSObject, jsobject, args[0]);
657 CONVERT_CHECKED(JSObject, proto, args[1]);
658
659 // Sanity checks. The old prototype (that we are replacing) could
660 // theoretically be null, but if it is not null then check that we
661 // didn't already install a hidden prototype here.
662 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
663 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
664 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
665
666 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000667 Object* map_or_failure;
668 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
669 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
670 return maybe_map_or_failure;
671 }
672 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000673 Map* new_proto_map = Map::cast(map_or_failure);
674
lrn@chromium.org303ada72010-10-27 09:33:13 +0000675 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
676 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
677 return maybe_map_or_failure;
678 }
679 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000680 Map* new_map = Map::cast(map_or_failure);
681
682 // Set proto's prototype to be the old prototype of the object.
683 new_proto_map->set_prototype(jsobject->GetPrototype());
684 proto->set_map(new_proto_map);
685 new_proto_map->set_is_hidden_prototype();
686
687 // Set the object's prototype to proto.
688 new_map->set_prototype(proto);
689 jsobject->set_map(new_map);
690
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000691 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000692}
693
694
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000695RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000697 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000698 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000699 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000700}
701
702
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000703// Recursively traverses hidden prototypes if property is not found
704static void GetOwnPropertyImplementation(JSObject* obj,
705 String* name,
706 LookupResult* result) {
707 obj->LocalLookupRealNamedProperty(name, result);
708
709 if (!result->IsProperty()) {
710 Object* proto = obj->GetPrototype();
711 if (proto->IsJSObject() &&
712 JSObject::cast(proto)->map()->is_hidden_prototype())
713 GetOwnPropertyImplementation(JSObject::cast(proto),
714 name, result);
715 }
716}
717
718
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000719static bool CheckAccessException(LookupResult* result,
720 v8::AccessType access_type) {
721 if (result->type() == CALLBACKS) {
722 Object* callback = result->GetCallbackObject();
723 if (callback->IsAccessorInfo()) {
724 AccessorInfo* info = AccessorInfo::cast(callback);
725 bool can_access =
726 (access_type == v8::ACCESS_HAS &&
727 (info->all_can_read() || info->all_can_write())) ||
728 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
729 (access_type == v8::ACCESS_SET && info->all_can_write());
730 return can_access;
731 }
732 }
733
734 return false;
735}
736
737
738static bool CheckAccess(JSObject* obj,
739 String* name,
740 LookupResult* result,
741 v8::AccessType access_type) {
742 ASSERT(result->IsProperty());
743
744 JSObject* holder = result->holder();
745 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000746 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000747 while (true) {
748 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000749 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000750 // Access check callback denied the access, but some properties
751 // can have a special permissions which override callbacks descision
752 // (currently see v8::AccessControl).
753 break;
754 }
755
756 if (current == holder) {
757 return true;
758 }
759
760 current = JSObject::cast(current->GetPrototype());
761 }
762
763 // API callbacks can have per callback access exceptions.
764 switch (result->type()) {
765 case CALLBACKS: {
766 if (CheckAccessException(result, access_type)) {
767 return true;
768 }
769 break;
770 }
771 case INTERCEPTOR: {
772 // If the object has an interceptor, try real named properties.
773 // Overwrite the result to fetch the correct property later.
774 holder->LookupRealNamedProperty(name, result);
775 if (result->IsProperty()) {
776 if (CheckAccessException(result, access_type)) {
777 return true;
778 }
779 }
780 break;
781 }
782 default:
783 break;
784 }
785
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000786 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000787 return false;
788}
789
790
791// TODO(1095): we should traverse hidden prototype hierachy as well.
792static bool CheckElementAccess(JSObject* obj,
793 uint32_t index,
794 v8::AccessType access_type) {
795 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000796 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000797 return false;
798 }
799
800 return true;
801}
802
803
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000804// Enumerator used as indices into the array returned from GetOwnProperty
805enum PropertyDescriptorIndices {
806 IS_ACCESSOR_INDEX,
807 VALUE_INDEX,
808 GETTER_INDEX,
809 SETTER_INDEX,
810 WRITABLE_INDEX,
811 ENUMERABLE_INDEX,
812 CONFIGURABLE_INDEX,
813 DESCRIPTOR_SIZE
814};
815
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000816// Returns an array with the property description:
817// if args[1] is not a property on args[0]
818// returns undefined
819// if args[1] is a data property on args[0]
820// [false, value, Writeable, Enumerable, Configurable]
821// if args[1] is an accessor on args[0]
822// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000823RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000824 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000825 Heap* heap = isolate->heap();
826 HandleScope scope(isolate);
827 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
828 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000829 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000830 CONVERT_ARG_CHECKED(JSObject, obj, 0);
831 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000832
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000833 // This could be an element.
834 uint32_t index;
835 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000836 switch (obj->HasLocalElement(index)) {
837 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000838 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000839
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000840 case JSObject::STRING_CHARACTER_ELEMENT: {
841 // Special handling of string objects according to ECMAScript 5
842 // 15.5.5.2. Note that this might be a string object with elements
843 // other than the actual string value. This is covered by the
844 // subsequent cases.
845 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
846 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000847 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000848
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000849 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000850 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000851 elms->set(WRITABLE_INDEX, heap->false_value());
852 elms->set(ENUMERABLE_INDEX, heap->false_value());
853 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000854 return *desc;
855 }
856
857 case JSObject::INTERCEPTED_ELEMENT:
858 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000859 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000860 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000861 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000862 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000863 elms->set(WRITABLE_INDEX, heap->true_value());
864 elms->set(ENUMERABLE_INDEX, heap->true_value());
865 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000866 return *desc;
867 }
868
869 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000870 Handle<JSObject> holder = obj;
871 if (obj->IsJSGlobalProxy()) {
872 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000873 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000874 ASSERT(proto->IsJSGlobalObject());
875 holder = Handle<JSObject>(JSObject::cast(proto));
876 }
877 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000878 int entry = dictionary->FindEntry(index);
879 ASSERT(entry != NumberDictionary::kNotFound);
880 PropertyDetails details = dictionary->DetailsAt(entry);
881 switch (details.type()) {
882 case CALLBACKS: {
883 // This is an accessor property with getter and/or setter.
884 FixedArray* callbacks =
885 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000886 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000887 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
888 elms->set(GETTER_INDEX, callbacks->get(0));
889 }
890 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
891 elms->set(SETTER_INDEX, callbacks->get(1));
892 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000893 break;
894 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000895 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000896 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000897 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000898 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000899 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000900 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000901 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000902 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000903 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000904 default:
905 UNREACHABLE();
906 break;
907 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000908 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
909 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000910 return *desc;
911 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000912 }
913 }
914
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000915 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000916 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000917
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000918 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000919 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000920 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000921
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000922 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000923 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000924 }
925
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000926 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
927 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000928
929 bool is_js_accessor = (result.type() == CALLBACKS) &&
930 (result.GetCallbackObject()->IsFixedArray());
931
932 if (is_js_accessor) {
933 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000934 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000935
936 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
937 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
938 elms->set(GETTER_INDEX, structure->get(0));
939 }
940 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
941 elms->set(SETTER_INDEX, structure->get(1));
942 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000943 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000944 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
945 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000946
947 PropertyAttributes attrs;
948 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000949 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000950 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
951 if (!maybe_value->ToObject(&value)) return maybe_value;
952 }
953 elms->set(VALUE_INDEX, value);
954 }
955
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000956 return *desc;
957}
958
959
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000960RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000961 ASSERT(args.length() == 1);
962 CONVERT_CHECKED(JSObject, obj, args[0]);
963 return obj->PreventExtensions();
964}
965
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000967RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000968 ASSERT(args.length() == 1);
969 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000970 if (obj->IsJSGlobalProxy()) {
971 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000972 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000973 ASSERT(proto->IsJSGlobalObject());
974 obj = JSObject::cast(proto);
975 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000976 return obj->map()->is_extensible() ? isolate->heap()->true_value()
977 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000978}
979
980
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000981RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000982 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000983 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000984 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
985 CONVERT_ARG_CHECKED(String, pattern, 1);
986 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000987 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
988 if (result.is_null()) return Failure::Exception();
989 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000990}
991
992
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000993RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000994 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000995 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000996 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000997 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998}
999
1000
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001001RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001002 ASSERT(args.length() == 1);
1003 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001004 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001005 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001006}
1007
1008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001009RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010 ASSERT(args.length() == 2);
1011 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001012 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001013 int index = field->value();
1014 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1015 InstanceType type = templ->map()->instance_type();
1016 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1017 type == OBJECT_TEMPLATE_INFO_TYPE);
1018 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001019 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001020 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1021 } else {
1022 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1023 }
1024 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001025}
1026
1027
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001028RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001029 ASSERT(args.length() == 1);
1030 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001031 Map* old_map = object->map();
1032 bool needs_access_checks = old_map->is_access_check_needed();
1033 if (needs_access_checks) {
1034 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001035 Object* new_map;
1036 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1037 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1038 }
ager@chromium.org32912102009-01-16 10:38:43 +00001039
1040 Map::cast(new_map)->set_is_access_check_needed(false);
1041 object->set_map(Map::cast(new_map));
1042 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001043 return needs_access_checks ? isolate->heap()->true_value()
1044 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001045}
1046
1047
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001048RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001049 ASSERT(args.length() == 1);
1050 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001051 Map* old_map = object->map();
1052 if (!old_map->is_access_check_needed()) {
1053 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001054 Object* new_map;
1055 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1056 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1057 }
ager@chromium.org32912102009-01-16 10:38:43 +00001058
1059 Map::cast(new_map)->set_is_access_check_needed(true);
1060 object->set_map(Map::cast(new_map));
1061 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001062 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001063}
1064
1065
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001066static Failure* ThrowRedeclarationError(Isolate* isolate,
1067 const char* type,
1068 Handle<String> name) {
1069 HandleScope scope(isolate);
1070 Handle<Object> type_handle =
1071 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001072 Handle<Object> args[2] = { type_handle, name };
1073 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001074 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1075 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001076}
1077
1078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001079RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001080 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001081 HandleScope scope(isolate);
1082 Handle<GlobalObject> global = Handle<GlobalObject>(
1083 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001084
ager@chromium.org3811b432009-10-28 14:53:37 +00001085 Handle<Context> context = args.at<Context>(0);
1086 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001087 bool is_eval = Smi::cast(args[2])->value() == 1;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001088 StrictModeFlag strict_mode =
1089 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1090 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001091
1092 // Compute the property attributes. According to ECMA-262, section
1093 // 13, page 71, the property must be read-only and
1094 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1095 // property as read-only, so we don't either.
1096 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1097
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098 // Traverse the name/value pairs and set the properties.
1099 int length = pairs->length();
1100 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001101 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001102 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001103 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001104
1105 // We have to declare a global const property. To capture we only
1106 // assign to it when evaluating the assignment for "const x =
1107 // <expr>" the initial value is the hole.
1108 bool is_const_property = value->IsTheHole();
1109
1110 if (value->IsUndefined() || is_const_property) {
1111 // Lookup the property in the global object, and don't set the
1112 // value of the variable if the property is already there.
1113 LookupResult lookup;
1114 global->Lookup(*name, &lookup);
1115 if (lookup.IsProperty()) {
1116 // Determine if the property is local by comparing the holder
1117 // against the global object. The information will be used to
1118 // avoid throwing re-declaration errors when declaring
1119 // variables or constants that exist in the prototype chain.
1120 bool is_local = (*global == lookup.holder());
1121 // Get the property attributes and determine if the property is
1122 // read-only.
1123 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1124 bool is_read_only = (attributes & READ_ONLY) != 0;
1125 if (lookup.type() == INTERCEPTOR) {
1126 // If the interceptor says the property is there, we
1127 // just return undefined without overwriting the property.
1128 // Otherwise, we continue to setting the property.
1129 if (attributes != ABSENT) {
1130 // Check if the existing property conflicts with regards to const.
1131 if (is_local && (is_read_only || is_const_property)) {
1132 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001133 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001134 };
1135 // The property already exists without conflicting: Go to
1136 // the next declaration.
1137 continue;
1138 }
1139 // Fall-through and introduce the absent property by using
1140 // SetProperty.
1141 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001142 // For const properties, we treat a callback with this name
1143 // even in the prototype as a conflicting declaration.
1144 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001145 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001146 }
1147 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001148 if (is_local && (is_read_only || is_const_property)) {
1149 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001150 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001151 }
1152 // The property already exists without conflicting: Go to
1153 // the next declaration.
1154 continue;
1155 }
1156 }
1157 } else {
1158 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001159 Handle<SharedFunctionInfo> shared =
1160 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001161 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001162 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1163 context,
1164 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001165 value = function;
1166 }
1167
1168 LookupResult lookup;
1169 global->LocalLookup(*name, &lookup);
1170
1171 PropertyAttributes attributes = is_const_property
1172 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1173 : base;
1174
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001175 // There's a local property that we need to overwrite because
1176 // we're either declaring a function or there's an interceptor
1177 // that claims the property is absent.
1178 //
1179 // Check for conflicting re-declarations. We cannot have
1180 // conflicting types in case of intercepted properties because
1181 // they are absent.
1182 if (lookup.IsProperty() &&
1183 (lookup.type() != INTERCEPTOR) &&
1184 (lookup.IsReadOnly() || is_const_property)) {
1185 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001186 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001187 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001188
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001189 // Safari does not allow the invocation of callback setters for
1190 // function declarations. To mimic this behavior, we do not allow
1191 // the invocation of setters for function values. This makes a
1192 // difference for global functions with the same names as event
1193 // handlers such as "function onload() {}". Firefox does call the
1194 // onload setter in those case and Safari does not. We follow
1195 // Safari for compatibility.
1196 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001197 // Do not change DONT_DELETE to false from true.
1198 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1199 attributes = static_cast<PropertyAttributes>(
1200 attributes | (lookup.GetAttributes() & DONT_DELETE));
1201 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001202 RETURN_IF_EMPTY_HANDLE(isolate,
1203 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001204 name,
1205 value,
1206 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001207 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001208 RETURN_IF_EMPTY_HANDLE(isolate,
1209 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001210 name,
1211 value,
1212 attributes,
1213 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001214 }
1215 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001216
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001217 ASSERT(!isolate->has_pending_exception());
1218 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001219}
1220
1221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001222RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001223 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001224 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001225
ager@chromium.org7c537e22008-10-16 08:43:32 +00001226 CONVERT_ARG_CHECKED(Context, context, 0);
1227 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001228 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001229 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
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());
1235
1236 int index;
1237 PropertyAttributes attributes;
1238 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001239 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001240 context->Lookup(name, flags, &index, &attributes);
1241
1242 if (attributes != ABSENT) {
1243 // The name was declared before; check for conflicting
1244 // re-declarations: This is similar to the code in parser.cc in
1245 // the AstBuildingParser::Declare function.
1246 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1247 // Functions are not read-only.
1248 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1249 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001250 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001251 }
1252
1253 // Initialize it if necessary.
1254 if (*initial_value != NULL) {
1255 if (index >= 0) {
1256 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001257 // the function context or the arguments object.
1258 if (holder->IsContext()) {
1259 ASSERT(holder.is_identical_to(context));
1260 if (((attributes & READ_ONLY) == 0) ||
1261 context->get(index)->IsTheHole()) {
1262 context->set(index, *initial_value);
1263 }
1264 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001265 // The holder is an arguments object.
1266 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001267 Handle<Object> result = SetElement(arguments, index, initial_value,
1268 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001269 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001270 }
1271 } else {
1272 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001273 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001274 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001275 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001276 SetProperty(context_ext, name, initial_value,
1277 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278 }
1279 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001280
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001282 // The property is not in the function context. It needs to be
1283 // "declared" in the function context's extension context, or in the
1284 // global context.
1285 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001286 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001287 // The function context's extension context exists - use it.
1288 context_ext = Handle<JSObject>(context->extension());
1289 } else {
1290 // The function context's extension context does not exists - allocate
1291 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001292 context_ext = isolate->factory()->NewJSObject(
1293 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001294 // And store it in the extension slot.
1295 context->set_extension(*context_ext);
1296 }
1297 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298
ager@chromium.org7c537e22008-10-16 08:43:32 +00001299 // Declare the property by setting it to the initial value if provided,
1300 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1301 // constant declarations).
1302 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001303 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001304 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001305 // Declaring a const context slot is a conflicting declaration if
1306 // there is a callback with that name in a prototype. It is
1307 // allowed to introduce const variables in
1308 // JSContextExtensionObjects. They are treated specially in
1309 // SetProperty and no setters are invoked for those since they are
1310 // not real JSObjects.
1311 if (initial_value->IsTheHole() &&
1312 !context_ext->IsJSContextExtensionObject()) {
1313 LookupResult lookup;
1314 context_ext->Lookup(*name, &lookup);
1315 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001316 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001317 }
1318 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001319 RETURN_IF_EMPTY_HANDLE(isolate,
1320 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001321 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001322 }
1323
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001324 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325}
1326
1327
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001328RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001329 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001330 // args[0] == name
1331 // args[1] == strict_mode
1332 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001333
1334 // Determine if we need to assign to the variable if it already
1335 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001336 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1337 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338
1339 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001340 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001341 RUNTIME_ASSERT(args[1]->IsSmi());
1342 StrictModeFlag strict_mode =
1343 static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
1344 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);
1625 CONVERT_SMI_CHECKED(properties, args[1]);
1626 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.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001640 CONVERT_SMI_CHECKED(index, args[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);
1657 CONVERT_SMI_CHECKED(elements_count, args[0]);
1658 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);
1812 int index = Smi::cast(args[1])->value();
1813 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);
2038 CONVERT_SMI_CHECKED(num, args[1]);
2039 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 }
2341 private:
2342 enum PartType {
2343 SUBJECT_PREFIX = 1,
2344 SUBJECT_SUFFIX,
2345 SUBJECT_CAPTURE,
2346 REPLACEMENT_SUBSTRING,
2347 REPLACEMENT_STRING,
2348
2349 NUMBER_OF_PART_TYPES
2350 };
2351
2352 struct ReplacementPart {
2353 static inline ReplacementPart SubjectMatch() {
2354 return ReplacementPart(SUBJECT_CAPTURE, 0);
2355 }
2356 static inline ReplacementPart SubjectCapture(int capture_index) {
2357 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2358 }
2359 static inline ReplacementPart SubjectPrefix() {
2360 return ReplacementPart(SUBJECT_PREFIX, 0);
2361 }
2362 static inline ReplacementPart SubjectSuffix(int subject_length) {
2363 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2364 }
2365 static inline ReplacementPart ReplacementString() {
2366 return ReplacementPart(REPLACEMENT_STRING, 0);
2367 }
2368 static inline ReplacementPart ReplacementSubString(int from, int to) {
2369 ASSERT(from >= 0);
2370 ASSERT(to > from);
2371 return ReplacementPart(-from, to);
2372 }
2373
2374 // If tag <= 0 then it is the negation of a start index of a substring of
2375 // the replacement pattern, otherwise it's a value from PartType.
2376 ReplacementPart(int tag, int data)
2377 : tag(tag), data(data) {
2378 // Must be non-positive or a PartType value.
2379 ASSERT(tag < NUMBER_OF_PART_TYPES);
2380 }
2381 // Either a value of PartType or a non-positive number that is
2382 // the negation of an index into the replacement string.
2383 int tag;
2384 // The data value's interpretation depends on the value of tag:
2385 // tag == SUBJECT_PREFIX ||
2386 // tag == SUBJECT_SUFFIX: data is unused.
2387 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2388 // tag == REPLACEMENT_SUBSTRING ||
2389 // tag == REPLACEMENT_STRING: data is index into array of substrings
2390 // of the replacement string.
2391 // tag <= 0: Temporary representation of the substring of the replacement
2392 // string ranging over -tag .. data.
2393 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2394 // substring objects.
2395 int data;
2396 };
2397
2398 template<typename Char>
2399 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2400 Vector<Char> characters,
2401 int capture_count,
2402 int subject_length) {
2403 int length = characters.length();
2404 int last = 0;
2405 for (int i = 0; i < length; i++) {
2406 Char c = characters[i];
2407 if (c == '$') {
2408 int next_index = i + 1;
2409 if (next_index == length) { // No next character!
2410 break;
2411 }
2412 Char c2 = characters[next_index];
2413 switch (c2) {
2414 case '$':
2415 if (i > last) {
2416 // There is a substring before. Include the first "$".
2417 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2418 last = next_index + 1; // Continue after the second "$".
2419 } else {
2420 // Let the next substring start with the second "$".
2421 last = next_index;
2422 }
2423 i = next_index;
2424 break;
2425 case '`':
2426 if (i > last) {
2427 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2428 }
2429 parts->Add(ReplacementPart::SubjectPrefix());
2430 i = next_index;
2431 last = i + 1;
2432 break;
2433 case '\'':
2434 if (i > last) {
2435 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2436 }
2437 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2438 i = next_index;
2439 last = i + 1;
2440 break;
2441 case '&':
2442 if (i > last) {
2443 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2444 }
2445 parts->Add(ReplacementPart::SubjectMatch());
2446 i = next_index;
2447 last = i + 1;
2448 break;
2449 case '0':
2450 case '1':
2451 case '2':
2452 case '3':
2453 case '4':
2454 case '5':
2455 case '6':
2456 case '7':
2457 case '8':
2458 case '9': {
2459 int capture_ref = c2 - '0';
2460 if (capture_ref > capture_count) {
2461 i = next_index;
2462 continue;
2463 }
2464 int second_digit_index = next_index + 1;
2465 if (second_digit_index < length) {
2466 // Peek ahead to see if we have two digits.
2467 Char c3 = characters[second_digit_index];
2468 if ('0' <= c3 && c3 <= '9') { // Double digits.
2469 int double_digit_ref = capture_ref * 10 + c3 - '0';
2470 if (double_digit_ref <= capture_count) {
2471 next_index = second_digit_index;
2472 capture_ref = double_digit_ref;
2473 }
2474 }
2475 }
2476 if (capture_ref > 0) {
2477 if (i > last) {
2478 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2479 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002480 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002481 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2482 last = next_index + 1;
2483 }
2484 i = next_index;
2485 break;
2486 }
2487 default:
2488 i = next_index;
2489 break;
2490 }
2491 }
2492 }
2493 if (length > last) {
2494 if (last == 0) {
2495 parts->Add(ReplacementPart::ReplacementString());
2496 } else {
2497 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2498 }
2499 }
2500 }
2501
2502 ZoneList<ReplacementPart> parts_;
2503 ZoneList<Handle<String> > replacement_substrings_;
2504};
2505
2506
2507void CompiledReplacement::Compile(Handle<String> replacement,
2508 int capture_count,
2509 int subject_length) {
2510 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002511 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002512 AssertNoAllocation no_alloc;
2513 ParseReplacementPattern(&parts_,
2514 replacement->ToAsciiVector(),
2515 capture_count,
2516 subject_length);
2517 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002518 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002519 AssertNoAllocation no_alloc;
2520
2521 ParseReplacementPattern(&parts_,
2522 replacement->ToUC16Vector(),
2523 capture_count,
2524 subject_length);
2525 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002526 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002527 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002528 int substring_index = 0;
2529 for (int i = 0, n = parts_.length(); i < n; i++) {
2530 int tag = parts_[i].tag;
2531 if (tag <= 0) { // A replacement string slice.
2532 int from = -tag;
2533 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002534 replacement_substrings_.Add(
2535 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002536 parts_[i].tag = REPLACEMENT_SUBSTRING;
2537 parts_[i].data = substring_index;
2538 substring_index++;
2539 } else if (tag == REPLACEMENT_STRING) {
2540 replacement_substrings_.Add(replacement);
2541 parts_[i].data = substring_index;
2542 substring_index++;
2543 }
2544 }
2545}
2546
2547
2548void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2549 int match_from,
2550 int match_to,
2551 Handle<JSArray> last_match_info) {
2552 for (int i = 0, n = parts_.length(); i < n; i++) {
2553 ReplacementPart part = parts_[i];
2554 switch (part.tag) {
2555 case SUBJECT_PREFIX:
2556 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2557 break;
2558 case SUBJECT_SUFFIX: {
2559 int subject_length = part.data;
2560 if (match_to < subject_length) {
2561 builder->AddSubjectSlice(match_to, subject_length);
2562 }
2563 break;
2564 }
2565 case SUBJECT_CAPTURE: {
2566 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002567 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002568 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2569 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2570 if (from >= 0 && to > from) {
2571 builder->AddSubjectSlice(from, to);
2572 }
2573 break;
2574 }
2575 case REPLACEMENT_SUBSTRING:
2576 case REPLACEMENT_STRING:
2577 builder->AddString(replacement_substrings_[part.data]);
2578 break;
2579 default:
2580 UNREACHABLE();
2581 }
2582 }
2583}
2584
2585
2586
lrn@chromium.org303ada72010-10-27 09:33:13 +00002587MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002588 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002589 String* subject,
2590 JSRegExp* regexp,
2591 String* replacement,
2592 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002593 ASSERT(subject->IsFlat());
2594 ASSERT(replacement->IsFlat());
2595
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002596 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002597
2598 int length = subject->length();
2599 Handle<String> subject_handle(subject);
2600 Handle<JSRegExp> regexp_handle(regexp);
2601 Handle<String> replacement_handle(replacement);
2602 Handle<JSArray> last_match_info_handle(last_match_info);
2603 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2604 subject_handle,
2605 0,
2606 last_match_info_handle);
2607 if (match.is_null()) {
2608 return Failure::Exception();
2609 }
2610 if (match->IsNull()) {
2611 return *subject_handle;
2612 }
2613
2614 int capture_count = regexp_handle->CaptureCount();
2615
2616 // CompiledReplacement uses zone allocation.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002617 CompilationZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002618 CompiledReplacement compiled_replacement;
2619 compiled_replacement.Compile(replacement_handle,
2620 capture_count,
2621 length);
2622
2623 bool is_global = regexp_handle->GetFlags().is_global();
2624
2625 // Guessing the number of parts that the final result string is built
2626 // from. Global regexps can match any number of times, so we guess
2627 // conservatively.
2628 int expected_parts =
2629 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002630 ReplacementStringBuilder builder(isolate->heap(),
2631 subject_handle,
2632 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002633
2634 // Index of end of last match.
2635 int prev = 0;
2636
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002637 // Number of parts added by compiled replacement plus preceeding
2638 // string and possibly suffix after last match. It is possible for
2639 // all components to use two elements when encoded as two smis.
2640 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002641 bool matched = true;
2642 do {
2643 ASSERT(last_match_info_handle->HasFastElements());
2644 // Increase the capacity of the builder before entering local handle-scope,
2645 // so its internal buffer can safely allocate a new handle if it grows.
2646 builder.EnsureCapacity(parts_added_per_loop);
2647
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002648 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002649 int start, end;
2650 {
2651 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002652 FixedArray* match_info_array =
2653 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002654
2655 ASSERT_EQ(capture_count * 2 + 2,
2656 RegExpImpl::GetLastCaptureCount(match_info_array));
2657 start = RegExpImpl::GetCapture(match_info_array, 0);
2658 end = RegExpImpl::GetCapture(match_info_array, 1);
2659 }
2660
2661 if (prev < start) {
2662 builder.AddSubjectSlice(prev, start);
2663 }
2664 compiled_replacement.Apply(&builder,
2665 start,
2666 end,
2667 last_match_info_handle);
2668 prev = end;
2669
2670 // Only continue checking for global regexps.
2671 if (!is_global) break;
2672
2673 // Continue from where the match ended, unless it was an empty match.
2674 int next = end;
2675 if (start == end) {
2676 next = end + 1;
2677 if (next > length) break;
2678 }
2679
2680 match = RegExpImpl::Exec(regexp_handle,
2681 subject_handle,
2682 next,
2683 last_match_info_handle);
2684 if (match.is_null()) {
2685 return Failure::Exception();
2686 }
2687 matched = !match->IsNull();
2688 } while (matched);
2689
2690 if (prev < length) {
2691 builder.AddSubjectSlice(prev, length);
2692 }
2693
2694 return *(builder.ToString());
2695}
2696
2697
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002698template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002699MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002700 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002701 String* subject,
2702 JSRegExp* regexp,
2703 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002704 ASSERT(subject->IsFlat());
2705
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002706 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002707
2708 Handle<String> subject_handle(subject);
2709 Handle<JSRegExp> regexp_handle(regexp);
2710 Handle<JSArray> last_match_info_handle(last_match_info);
2711 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2712 subject_handle,
2713 0,
2714 last_match_info_handle);
2715 if (match.is_null()) return Failure::Exception();
2716 if (match->IsNull()) return *subject_handle;
2717
2718 ASSERT(last_match_info_handle->HasFastElements());
2719
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002720 int start, end;
2721 {
2722 AssertNoAllocation match_info_array_is_not_in_a_handle;
2723 FixedArray* match_info_array =
2724 FixedArray::cast(last_match_info_handle->elements());
2725
2726 start = RegExpImpl::GetCapture(match_info_array, 0);
2727 end = RegExpImpl::GetCapture(match_info_array, 1);
2728 }
2729
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002730 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002731 int new_length = length - (end - start);
2732 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002733 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002734 }
2735 Handle<ResultSeqString> answer;
2736 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002737 answer = Handle<ResultSeqString>::cast(
2738 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002739 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002740 answer = Handle<ResultSeqString>::cast(
2741 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002742 }
2743
2744 // If the regexp isn't global, only match once.
2745 if (!regexp_handle->GetFlags().is_global()) {
2746 if (start > 0) {
2747 String::WriteToFlat(*subject_handle,
2748 answer->GetChars(),
2749 0,
2750 start);
2751 }
2752 if (end < length) {
2753 String::WriteToFlat(*subject_handle,
2754 answer->GetChars() + start,
2755 end,
2756 length);
2757 }
2758 return *answer;
2759 }
2760
2761 int prev = 0; // Index of end of last match.
2762 int next = 0; // Start of next search (prev unless last match was empty).
2763 int position = 0;
2764
2765 do {
2766 if (prev < start) {
2767 // Add substring subject[prev;start] to answer string.
2768 String::WriteToFlat(*subject_handle,
2769 answer->GetChars() + position,
2770 prev,
2771 start);
2772 position += start - prev;
2773 }
2774 prev = end;
2775 next = end;
2776 // Continue from where the match ended, unless it was an empty match.
2777 if (start == end) {
2778 next++;
2779 if (next > length) break;
2780 }
2781 match = RegExpImpl::Exec(regexp_handle,
2782 subject_handle,
2783 next,
2784 last_match_info_handle);
2785 if (match.is_null()) return Failure::Exception();
2786 if (match->IsNull()) break;
2787
2788 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002789 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002790 {
2791 AssertNoAllocation match_info_array_is_not_in_a_handle;
2792 FixedArray* match_info_array =
2793 FixedArray::cast(last_match_info_handle->elements());
2794 start = RegExpImpl::GetCapture(match_info_array, 0);
2795 end = RegExpImpl::GetCapture(match_info_array, 1);
2796 }
2797 } while (true);
2798
2799 if (prev < length) {
2800 // Add substring subject[prev;length] to answer string.
2801 String::WriteToFlat(*subject_handle,
2802 answer->GetChars() + position,
2803 prev,
2804 length);
2805 position += length - prev;
2806 }
2807
2808 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002809 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002810 }
2811
2812 // Shorten string and fill
2813 int string_size = ResultSeqString::SizeFor(position);
2814 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2815 int delta = allocated_string_size - string_size;
2816
2817 answer->set_length(position);
2818 if (delta == 0) return *answer;
2819
2820 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002821 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002822
2823 return *answer;
2824}
2825
2826
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002827RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002828 ASSERT(args.length() == 4);
2829
2830 CONVERT_CHECKED(String, subject, args[0]);
2831 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002832 Object* flat_subject;
2833 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2834 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2835 return maybe_flat_subject;
2836 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002837 }
2838 subject = String::cast(flat_subject);
2839 }
2840
2841 CONVERT_CHECKED(String, replacement, args[2]);
2842 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002843 Object* flat_replacement;
2844 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2845 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2846 return maybe_flat_replacement;
2847 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002848 }
2849 replacement = String::cast(flat_replacement);
2850 }
2851
2852 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2853 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2854
2855 ASSERT(last_match_info->HasFastElements());
2856
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002857 if (replacement->length() == 0) {
2858 if (subject->HasOnlyAsciiChars()) {
2859 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002860 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002861 } else {
2862 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002863 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002864 }
2865 }
2866
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002867 return StringReplaceRegExpWithString(isolate,
2868 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002869 regexp,
2870 replacement,
2871 last_match_info);
2872}
2873
2874
ager@chromium.org7c537e22008-10-16 08:43:32 +00002875// Perform string match of pattern on subject, starting at start index.
2876// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002877// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002878int Runtime::StringMatch(Isolate* isolate,
2879 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002880 Handle<String> pat,
2881 int start_index) {
2882 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002883 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002884
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002885 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002886 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002887
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002888 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002889 if (start_index + pattern_length > subject_length) return -1;
2890
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002891 if (!sub->IsFlat()) FlattenString(sub);
2892 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002893
ager@chromium.org7c537e22008-10-16 08:43:32 +00002894 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002895 // Extract flattened substrings of cons strings before determining asciiness.
2896 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002897 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002898 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002899 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002900
ager@chromium.org7c537e22008-10-16 08:43:32 +00002901 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002902 if (seq_pat->IsAsciiRepresentation()) {
2903 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2904 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002905 return SearchString(isolate,
2906 seq_sub->ToAsciiVector(),
2907 pat_vector,
2908 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002909 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002910 return SearchString(isolate,
2911 seq_sub->ToUC16Vector(),
2912 pat_vector,
2913 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002914 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002915 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2916 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002917 return SearchString(isolate,
2918 seq_sub->ToAsciiVector(),
2919 pat_vector,
2920 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002921 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002922 return SearchString(isolate,
2923 seq_sub->ToUC16Vector(),
2924 pat_vector,
2925 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002926}
2927
2928
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002929RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002930 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002931 ASSERT(args.length() == 3);
2932
ager@chromium.org7c537e22008-10-16 08:43:32 +00002933 CONVERT_ARG_CHECKED(String, sub, 0);
2934 CONVERT_ARG_CHECKED(String, pat, 1);
2935
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002936 Object* index = args[2];
2937 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002938 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002939
ager@chromium.org870a0b62008-11-04 11:43:05 +00002940 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002941 int position =
2942 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002943 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002944}
2945
2946
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002947template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002948static int StringMatchBackwards(Vector<const schar> subject,
2949 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002950 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002951 int pattern_length = pattern.length();
2952 ASSERT(pattern_length >= 1);
2953 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002954
2955 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002956 for (int i = 0; i < pattern_length; i++) {
2957 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002958 if (c > String::kMaxAsciiCharCode) {
2959 return -1;
2960 }
2961 }
2962 }
2963
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002964 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002965 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002966 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002967 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002968 while (j < pattern_length) {
2969 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002970 break;
2971 }
2972 j++;
2973 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002974 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002975 return i;
2976 }
2977 }
2978 return -1;
2979}
2980
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002981RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002982 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002983 ASSERT(args.length() == 3);
2984
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002985 CONVERT_ARG_CHECKED(String, sub, 0);
2986 CONVERT_ARG_CHECKED(String, pat, 1);
2987
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002988 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002989 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002990 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002991
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002992 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002993 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002994
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002995 if (start_index + pat_length > sub_length) {
2996 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002997 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002998
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002999 if (pat_length == 0) {
3000 return Smi::FromInt(start_index);
3001 }
3002
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003003 if (!sub->IsFlat()) FlattenString(sub);
3004 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003005
3006 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3007
3008 int position = -1;
3009
3010 if (pat->IsAsciiRepresentation()) {
3011 Vector<const char> pat_vector = pat->ToAsciiVector();
3012 if (sub->IsAsciiRepresentation()) {
3013 position = StringMatchBackwards(sub->ToAsciiVector(),
3014 pat_vector,
3015 start_index);
3016 } else {
3017 position = StringMatchBackwards(sub->ToUC16Vector(),
3018 pat_vector,
3019 start_index);
3020 }
3021 } else {
3022 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3023 if (sub->IsAsciiRepresentation()) {
3024 position = StringMatchBackwards(sub->ToAsciiVector(),
3025 pat_vector,
3026 start_index);
3027 } else {
3028 position = StringMatchBackwards(sub->ToUC16Vector(),
3029 pat_vector,
3030 start_index);
3031 }
3032 }
3033
3034 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003035}
3036
3037
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003038RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003039 NoHandleAllocation ha;
3040 ASSERT(args.length() == 2);
3041
3042 CONVERT_CHECKED(String, str1, args[0]);
3043 CONVERT_CHECKED(String, str2, args[1]);
3044
3045 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003046 int str1_length = str1->length();
3047 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003048
3049 // Decide trivial cases without flattening.
3050 if (str1_length == 0) {
3051 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3052 return Smi::FromInt(-str2_length);
3053 } else {
3054 if (str2_length == 0) return Smi::FromInt(str1_length);
3055 }
3056
3057 int end = str1_length < str2_length ? str1_length : str2_length;
3058
3059 // No need to flatten if we are going to find the answer on the first
3060 // character. At this point we know there is at least one character
3061 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003062 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003063 if (d != 0) return Smi::FromInt(d);
3064
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003065 str1->TryFlatten();
3066 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003067
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003068 StringInputBuffer& buf1 =
3069 *isolate->runtime_state()->string_locale_compare_buf1();
3070 StringInputBuffer& buf2 =
3071 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003072
3073 buf1.Reset(str1);
3074 buf2.Reset(str2);
3075
3076 for (int i = 0; i < end; i++) {
3077 uint16_t char1 = buf1.GetNext();
3078 uint16_t char2 = buf2.GetNext();
3079 if (char1 != char2) return Smi::FromInt(char1 - char2);
3080 }
3081
3082 return Smi::FromInt(str1_length - str2_length);
3083}
3084
3085
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003086RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003087 NoHandleAllocation ha;
3088 ASSERT(args.length() == 3);
3089
3090 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003091 Object* from = args[1];
3092 Object* to = args[2];
3093 int start, end;
3094 // We have a fast integer-only case here to avoid a conversion to double in
3095 // the common case where from and to are Smis.
3096 if (from->IsSmi() && to->IsSmi()) {
3097 start = Smi::cast(from)->value();
3098 end = Smi::cast(to)->value();
3099 } else {
3100 CONVERT_DOUBLE_CHECKED(from_number, from);
3101 CONVERT_DOUBLE_CHECKED(to_number, to);
3102 start = FastD2I(from_number);
3103 end = FastD2I(to_number);
3104 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003105 RUNTIME_ASSERT(end >= start);
3106 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003107 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003108 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003109 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003110}
3111
3112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003113RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003114 ASSERT_EQ(3, args.length());
3115
3116 CONVERT_ARG_CHECKED(String, subject, 0);
3117 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3118 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3119 HandleScope handles;
3120
3121 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3122
3123 if (match.is_null()) {
3124 return Failure::Exception();
3125 }
3126 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003127 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003128 }
3129 int length = subject->length();
3130
danno@chromium.org40cb8782011-05-25 07:58:50 +00003131 CompilationZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003132 ZoneList<int> offsets(8);
3133 do {
3134 int start;
3135 int end;
3136 {
3137 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003138 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003139 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3140 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3141 }
3142 offsets.Add(start);
3143 offsets.Add(end);
3144 int index = start < end ? end : end + 1;
3145 if (index > length) break;
3146 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3147 if (match.is_null()) {
3148 return Failure::Exception();
3149 }
3150 } while (!match->IsNull());
3151 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003152 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org41826e72009-03-30 13:30:57 +00003153 for (int i = 0; i < matches ; i++) {
3154 int from = offsets.at(i * 2);
3155 int to = offsets.at(i * 2 + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003156 Handle<String> match = isolate->factory()->NewSubString(subject, from, to);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003157 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00003158 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003159 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003160 result->set_length(Smi::FromInt(matches));
3161 return *result;
3162}
3163
3164
lrn@chromium.org25156de2010-04-06 13:10:27 +00003165// Two smis before and after the match, for very long strings.
3166const int kMaxBuilderEntriesPerRegExpMatch = 5;
3167
3168
3169static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3170 Handle<JSArray> last_match_info,
3171 int match_start,
3172 int match_end) {
3173 // Fill last_match_info with a single capture.
3174 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3175 AssertNoAllocation no_gc;
3176 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3177 RegExpImpl::SetLastCaptureCount(elements, 2);
3178 RegExpImpl::SetLastInput(elements, *subject);
3179 RegExpImpl::SetLastSubject(elements, *subject);
3180 RegExpImpl::SetCapture(elements, 0, match_start);
3181 RegExpImpl::SetCapture(elements, 1, match_end);
3182}
3183
3184
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003185template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003186static bool SearchStringMultiple(Isolate* isolate,
3187 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003188 Vector<const PatternChar> pattern,
3189 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003190 FixedArrayBuilder* builder,
3191 int* match_pos) {
3192 int pos = *match_pos;
3193 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003194 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003195 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003196 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003197 while (pos <= max_search_start) {
3198 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3199 *match_pos = pos;
3200 return false;
3201 }
3202 // Position of end of previous match.
3203 int match_end = pos + pattern_length;
3204 int new_pos = search.Search(subject, match_end);
3205 if (new_pos >= 0) {
3206 // A match.
3207 if (new_pos > match_end) {
3208 ReplacementStringBuilder::AddSubjectSlice(builder,
3209 match_end,
3210 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003211 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003212 pos = new_pos;
3213 builder->Add(pattern_string);
3214 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003215 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003216 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003217 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003218
lrn@chromium.org25156de2010-04-06 13:10:27 +00003219 if (pos < max_search_start) {
3220 ReplacementStringBuilder::AddSubjectSlice(builder,
3221 pos + pattern_length,
3222 subject_length);
3223 }
3224 *match_pos = pos;
3225 return true;
3226}
3227
3228
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003229static bool SearchStringMultiple(Isolate* isolate,
3230 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003231 Handle<String> pattern,
3232 Handle<JSArray> last_match_info,
3233 FixedArrayBuilder* builder) {
3234 ASSERT(subject->IsFlat());
3235 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003236
3237 // Treating as if a previous match was before first character.
3238 int match_pos = -pattern->length();
3239
3240 for (;;) { // Break when search complete.
3241 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3242 AssertNoAllocation no_gc;
3243 if (subject->IsAsciiRepresentation()) {
3244 Vector<const char> subject_vector = subject->ToAsciiVector();
3245 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003246 if (SearchStringMultiple(isolate,
3247 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003248 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003249 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003250 builder,
3251 &match_pos)) break;
3252 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003253 if (SearchStringMultiple(isolate,
3254 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003255 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003256 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003257 builder,
3258 &match_pos)) break;
3259 }
3260 } else {
3261 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3262 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003263 if (SearchStringMultiple(isolate,
3264 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003265 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003266 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003267 builder,
3268 &match_pos)) break;
3269 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003270 if (SearchStringMultiple(isolate,
3271 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003272 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003273 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003274 builder,
3275 &match_pos)) break;
3276 }
3277 }
3278 }
3279
3280 if (match_pos >= 0) {
3281 SetLastMatchInfoNoCaptures(subject,
3282 last_match_info,
3283 match_pos,
3284 match_pos + pattern->length());
3285 return true;
3286 }
3287 return false; // No matches at all.
3288}
3289
3290
3291static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003292 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003293 Handle<String> subject,
3294 Handle<JSRegExp> regexp,
3295 Handle<JSArray> last_match_array,
3296 FixedArrayBuilder* builder) {
3297 ASSERT(subject->IsFlat());
3298 int match_start = -1;
3299 int match_end = 0;
3300 int pos = 0;
3301 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3302 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3303
3304 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003305 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003306 int subject_length = subject->length();
3307
3308 for (;;) { // Break on failure, return on exception.
3309 RegExpImpl::IrregexpResult result =
3310 RegExpImpl::IrregexpExecOnce(regexp,
3311 subject,
3312 pos,
3313 register_vector);
3314 if (result == RegExpImpl::RE_SUCCESS) {
3315 match_start = register_vector[0];
3316 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3317 if (match_end < match_start) {
3318 ReplacementStringBuilder::AddSubjectSlice(builder,
3319 match_end,
3320 match_start);
3321 }
3322 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003323 HandleScope loop_scope(isolate);
3324 builder->Add(*isolate->factory()->NewSubString(subject,
3325 match_start,
3326 match_end));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003327 if (match_start != match_end) {
3328 pos = match_end;
3329 } else {
3330 pos = match_end + 1;
3331 if (pos > subject_length) break;
3332 }
3333 } else if (result == RegExpImpl::RE_FAILURE) {
3334 break;
3335 } else {
3336 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3337 return result;
3338 }
3339 }
3340
3341 if (match_start >= 0) {
3342 if (match_end < subject_length) {
3343 ReplacementStringBuilder::AddSubjectSlice(builder,
3344 match_end,
3345 subject_length);
3346 }
3347 SetLastMatchInfoNoCaptures(subject,
3348 last_match_array,
3349 match_start,
3350 match_end);
3351 return RegExpImpl::RE_SUCCESS;
3352 } else {
3353 return RegExpImpl::RE_FAILURE; // No matches at all.
3354 }
3355}
3356
3357
3358static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003359 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003360 Handle<String> subject,
3361 Handle<JSRegExp> regexp,
3362 Handle<JSArray> last_match_array,
3363 FixedArrayBuilder* builder) {
3364
3365 ASSERT(subject->IsFlat());
3366 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3367 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3368
3369 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003370 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003371
3372 RegExpImpl::IrregexpResult result =
3373 RegExpImpl::IrregexpExecOnce(regexp,
3374 subject,
3375 0,
3376 register_vector);
3377
3378 int capture_count = regexp->CaptureCount();
3379 int subject_length = subject->length();
3380
3381 // Position to search from.
3382 int pos = 0;
3383 // End of previous match. Differs from pos if match was empty.
3384 int match_end = 0;
3385 if (result == RegExpImpl::RE_SUCCESS) {
3386 // Need to keep a copy of the previous match for creating last_match_info
3387 // at the end, so we have two vectors that we swap between.
3388 OffsetsVector registers2(required_registers);
3389 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3390
3391 do {
3392 int match_start = register_vector[0];
3393 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3394 if (match_end < match_start) {
3395 ReplacementStringBuilder::AddSubjectSlice(builder,
3396 match_end,
3397 match_start);
3398 }
3399 match_end = register_vector[1];
3400
3401 {
3402 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003403 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003404 // Arguments array to replace function is match, captures, index and
3405 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003406 Handle<FixedArray> elements =
3407 isolate->factory()->NewFixedArray(3 + capture_count);
3408 Handle<String> match = isolate->factory()->NewSubString(subject,
3409 match_start,
3410 match_end);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003411 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003412 for (int i = 1; i <= capture_count; i++) {
3413 int start = register_vector[i * 2];
3414 if (start >= 0) {
3415 int end = register_vector[i * 2 + 1];
3416 ASSERT(start <= end);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003417 Handle<String> substring = isolate->factory()->NewSubString(subject,
3418 start,
3419 end);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003420 elements->set(i, *substring);
3421 } else {
3422 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003423 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003424 }
3425 }
3426 elements->set(capture_count + 1, Smi::FromInt(match_start));
3427 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003428 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003429 }
3430 // Swap register vectors, so the last successful match is in
3431 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003432 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003433 prev_register_vector = register_vector;
3434 register_vector = tmp;
3435
3436 if (match_end > match_start) {
3437 pos = match_end;
3438 } else {
3439 pos = match_end + 1;
3440 if (pos > subject_length) {
3441 break;
3442 }
3443 }
3444
3445 result = RegExpImpl::IrregexpExecOnce(regexp,
3446 subject,
3447 pos,
3448 register_vector);
3449 } while (result == RegExpImpl::RE_SUCCESS);
3450
3451 if (result != RegExpImpl::RE_EXCEPTION) {
3452 // Finished matching, with at least one match.
3453 if (match_end < subject_length) {
3454 ReplacementStringBuilder::AddSubjectSlice(builder,
3455 match_end,
3456 subject_length);
3457 }
3458
3459 int last_match_capture_count = (capture_count + 1) * 2;
3460 int last_match_array_size =
3461 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3462 last_match_array->EnsureSize(last_match_array_size);
3463 AssertNoAllocation no_gc;
3464 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3465 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3466 RegExpImpl::SetLastSubject(elements, *subject);
3467 RegExpImpl::SetLastInput(elements, *subject);
3468 for (int i = 0; i < last_match_capture_count; i++) {
3469 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3470 }
3471 return RegExpImpl::RE_SUCCESS;
3472 }
3473 }
3474 // No matches at all, return failure or exception result directly.
3475 return result;
3476}
3477
3478
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003479RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003480 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003481 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003482
3483 CONVERT_ARG_CHECKED(String, subject, 1);
3484 if (!subject->IsFlat()) { FlattenString(subject); }
3485 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3486 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3487 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3488
3489 ASSERT(last_match_info->HasFastElements());
3490 ASSERT(regexp->GetFlags().is_global());
3491 Handle<FixedArray> result_elements;
3492 if (result_array->HasFastElements()) {
3493 result_elements =
3494 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3495 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003496 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003497 }
3498 FixedArrayBuilder builder(result_elements);
3499
3500 if (regexp->TypeTag() == JSRegExp::ATOM) {
3501 Handle<String> pattern(
3502 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003503 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003504 if (SearchStringMultiple(isolate, subject, pattern,
3505 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003506 return *builder.ToJSArray(result_array);
3507 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003508 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003509 }
3510
3511 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3512
3513 RegExpImpl::IrregexpResult result;
3514 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003515 result = SearchRegExpNoCaptureMultiple(isolate,
3516 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003517 regexp,
3518 last_match_info,
3519 &builder);
3520 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003521 result = SearchRegExpMultiple(isolate,
3522 subject,
3523 regexp,
3524 last_match_info,
3525 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003526 }
3527 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003528 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003529 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3530 return Failure::Exception();
3531}
3532
3533
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003534RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003535 NoHandleAllocation ha;
3536 ASSERT(args.length() == 2);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003537 CONVERT_SMI_CHECKED(radix, args[1]);
3538 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003539
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003540 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003541 if (args[0]->IsSmi()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003542 int value = Smi::cast(args[0])->value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003543 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003544 // Character array used for conversion.
3545 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003546 return isolate->heap()->
3547 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003548 }
3549 }
3550
3551 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003552 CONVERT_DOUBLE_CHECKED(value, args[0]);
3553 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003554 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003555 }
3556 if (isinf(value)) {
3557 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003558 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003559 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003560 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003561 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003562 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003563 MaybeObject* result =
3564 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003565 DeleteArray(str);
3566 return result;
3567}
3568
3569
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003570RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003571 NoHandleAllocation ha;
3572 ASSERT(args.length() == 2);
3573
3574 CONVERT_DOUBLE_CHECKED(value, args[0]);
3575 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003576 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003577 }
3578 if (isinf(value)) {
3579 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003580 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003581 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003582 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003583 }
3584 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3585 int f = FastD2I(f_number);
3586 RUNTIME_ASSERT(f >= 0);
3587 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003588 MaybeObject* res =
3589 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003590 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003591 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003592}
3593
3594
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003595RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003596 NoHandleAllocation ha;
3597 ASSERT(args.length() == 2);
3598
3599 CONVERT_DOUBLE_CHECKED(value, args[0]);
3600 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003601 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003602 }
3603 if (isinf(value)) {
3604 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003605 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003606 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003607 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003608 }
3609 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3610 int f = FastD2I(f_number);
3611 RUNTIME_ASSERT(f >= -1 && f <= 20);
3612 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003613 MaybeObject* res =
3614 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003615 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003616 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003617}
3618
3619
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003620RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003621 NoHandleAllocation ha;
3622 ASSERT(args.length() == 2);
3623
3624 CONVERT_DOUBLE_CHECKED(value, args[0]);
3625 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003626 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003627 }
3628 if (isinf(value)) {
3629 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003630 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003631 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003632 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003633 }
3634 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3635 int f = FastD2I(f_number);
3636 RUNTIME_ASSERT(f >= 1 && f <= 21);
3637 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003638 MaybeObject* res =
3639 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003640 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003641 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003642}
3643
3644
3645// Returns a single character string where first character equals
3646// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003647static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003648 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003649 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003650 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003651 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003652 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003653 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003654}
3655
3656
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003657MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3658 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003659 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003660 // Handle [] indexing on Strings
3661 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003662 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3663 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003664 }
3665
3666 // Handle [] indexing on String objects
3667 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003668 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3669 Handle<Object> result =
3670 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3671 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003672 }
3673
3674 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003675 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003676 return prototype->GetElement(index);
3677 }
3678
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003679 return GetElement(object, index);
3680}
3681
3682
lrn@chromium.org303ada72010-10-27 09:33:13 +00003683MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003684 return object->GetElement(index);
3685}
3686
3687
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003688MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3689 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003690 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003691 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003692
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003693 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003694 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003695 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003696 isolate->factory()->NewTypeError("non_object_property_load",
3697 HandleVector(args, 2));
3698 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003699 }
3700
3701 // Check if the given key is an array index.
3702 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003703 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003704 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003705 }
3706
3707 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003708 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003709 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003710 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003711 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003712 bool has_pending_exception = false;
3713 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003714 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003715 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003716 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003717 }
3718
ager@chromium.org32912102009-01-16 10:38:43 +00003719 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003720 // the element if so.
3721 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003722 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003723 } else {
3724 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003725 return object->GetProperty(*name, &attr);
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);
3797 int index = Smi::cast(args[1])->value();
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);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003890 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003891 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003892 }
3893
ager@chromium.org5c838252010-02-19 08:53:10 +00003894 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003895 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003896
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003897 // To be compatible with safari we do not change the value on API objects
3898 // in defineProperty. Firefox disagrees here, and actually changes the value.
3899 if (result.IsProperty() &&
3900 (result.type() == CALLBACKS) &&
3901 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003902 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003903 }
3904
ager@chromium.org5c838252010-02-19 08:53:10 +00003905 // Take special care when attributes are different and there is already
3906 // a property. For simplicity we normalize the property which enables us
3907 // to not worry about changing the instance_descriptor and creating a new
3908 // map. The current version of SetObjectProperty does not handle attributes
3909 // correctly in the case where a property is a field and is reset with
3910 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003911 if (result.IsProperty() &&
3912 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003913 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003914 if (js_object->IsJSGlobalProxy()) {
3915 // Since the result is a property, the prototype will exist so
3916 // we don't have to check for null.
3917 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003918 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003919 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003920 // Use IgnoreAttributes version since a readonly property may be
3921 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003922 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3923 *obj_value,
3924 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003925 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003926
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003927 return Runtime::ForceSetObjectProperty(isolate,
3928 js_object,
3929 name,
3930 obj_value,
3931 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003932}
3933
3934
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003935MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
3936 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003937 Handle<Object> key,
3938 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003939 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003940 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003941 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003942
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003943 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003944 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003945 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003946 isolate->factory()->NewTypeError("non_object_property_store",
3947 HandleVector(args, 2));
3948 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003949 }
3950
3951 // If the object isn't a JavaScript object, we ignore the store.
3952 if (!object->IsJSObject()) return *value;
3953
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003954 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3955
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003956 // Check if the given key is an array index.
3957 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003958 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003959 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3960 // of a string using [] notation. We need to support this too in
3961 // JavaScript.
3962 // In the case of a String object we just need to redirect the assignment to
3963 // the underlying string if the index is in range. Since the underlying
3964 // string does nothing with the assignment then we can ignore such
3965 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003966 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003967 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003968 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003969
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003970 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003971 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003972 return *value;
3973 }
3974
3975 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003976 Handle<Object> result;
3977 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003978 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003979 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003980 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003981 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003982 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003983 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003984 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003985 return *value;
3986 }
3987
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003988 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003989 bool has_pending_exception = false;
3990 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3991 if (has_pending_exception) return Failure::Exception();
3992 Handle<String> name = Handle<String>::cast(converted);
3993
3994 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003995 return js_object->SetElement(index, *value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003996 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003997 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003998 }
3999}
4000
4001
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004002MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4003 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004004 Handle<Object> key,
4005 Handle<Object> value,
4006 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004007 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004008
4009 // Check if the given key is an array index.
4010 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004011 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004012 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4013 // of a string using [] notation. We need to support this too in
4014 // JavaScript.
4015 // In the case of a String object we just need to redirect the assignment to
4016 // the underlying string if the index is in range. Since the underlying
4017 // string does nothing with the assignment then we can ignore such
4018 // assignments.
4019 if (js_object->IsStringObjectWithCharacterAt(index)) {
4020 return *value;
4021 }
4022
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004023 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004024 }
4025
4026 if (key->IsString()) {
4027 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004028 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004029 } else {
4030 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004031 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004032 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4033 *value,
4034 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004035 }
4036 }
4037
4038 // Call-back into JavaScript to convert the key to a string.
4039 bool has_pending_exception = false;
4040 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4041 if (has_pending_exception) return Failure::Exception();
4042 Handle<String> name = Handle<String>::cast(converted);
4043
4044 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004045 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004046 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004047 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004048 }
4049}
4050
4051
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004052MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4053 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004054 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004055 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004056
4057 // Check if the given key is an array index.
4058 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004059 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004060 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4061 // characters of a string using [] notation. In the case of a
4062 // String object we just need to redirect the deletion to the
4063 // underlying string if the index is in range. Since the
4064 // underlying string does nothing with the deletion, we can ignore
4065 // such deletions.
4066 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004067 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004068 }
4069
4070 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4071 }
4072
4073 Handle<String> key_string;
4074 if (key->IsString()) {
4075 key_string = Handle<String>::cast(key);
4076 } else {
4077 // Call-back into JavaScript to convert the key to a string.
4078 bool has_pending_exception = false;
4079 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4080 if (has_pending_exception) return Failure::Exception();
4081 key_string = Handle<String>::cast(converted);
4082 }
4083
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004084 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004085 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4086}
4087
4088
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004089RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004090 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004091 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004092
4093 Handle<Object> object = args.at<Object>(0);
4094 Handle<Object> key = args.at<Object>(1);
4095 Handle<Object> value = args.at<Object>(2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004096 CONVERT_SMI_CHECKED(unchecked_attributes, args[3]);
4097 RUNTIME_ASSERT(
4098 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004099 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004100 PropertyAttributes attributes =
4101 static_cast<PropertyAttributes>(unchecked_attributes);
4102
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004103 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004104 if (args.length() == 5) {
4105 CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
4106 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4107 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004108 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004110
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004111 return Runtime::SetObjectProperty(isolate,
4112 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004113 key,
4114 value,
4115 attributes,
4116 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004117}
4118
4119
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004120// Set the ES5 native flag on the function.
4121// This is used to decide if we should transform null and undefined
4122// into the global object when doing call and apply.
4123RUNTIME_FUNCTION(MaybeObject*, Runtime_SetES5Flag) {
4124 NoHandleAllocation ha;
4125 RUNTIME_ASSERT(args.length() == 1);
4126
4127 Handle<Object> object = args.at<Object>(0);
4128
4129 if (object->IsJSFunction()) {
4130 JSFunction* func = JSFunction::cast(*object);
4131 func->shared()->set_es5_native(true);
4132 }
4133 return isolate->heap()->undefined_value();
4134}
4135
4136
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004137// Set a local property, even if it is READ_ONLY. If the property does not
4138// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004139RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004140 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004141 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004142 CONVERT_CHECKED(JSObject, object, args[0]);
4143 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004144 // Compute attributes.
4145 PropertyAttributes attributes = NONE;
4146 if (args.length() == 4) {
4147 CONVERT_CHECKED(Smi, value_obj, args[3]);
4148 int unchecked_value = value_obj->value();
4149 // Only attribute bits should be set.
4150 RUNTIME_ASSERT(
4151 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4152 attributes = static_cast<PropertyAttributes>(unchecked_value);
4153 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004154
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004155 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004156 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004157}
4158
4159
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004160RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004161 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004162 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004163
4164 CONVERT_CHECKED(JSObject, object, args[0]);
4165 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004166 CONVERT_SMI_CHECKED(strict, args[2]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004167 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004168 ? JSObject::STRICT_DELETION
4169 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004170}
4171
4172
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004173static Object* HasLocalPropertyImplementation(Isolate* isolate,
4174 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004175 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004176 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004177 // Handle hidden prototypes. If there's a hidden prototype above this thing
4178 // then we have to check it for properties, because they are supposed to
4179 // look like they are on this object.
4180 Handle<Object> proto(object->GetPrototype());
4181 if (proto->IsJSObject() &&
4182 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004183 return HasLocalPropertyImplementation(isolate,
4184 Handle<JSObject>::cast(proto),
4185 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004186 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004187 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004188}
4189
4190
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004191RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004192 NoHandleAllocation ha;
4193 ASSERT(args.length() == 2);
4194 CONVERT_CHECKED(String, key, args[1]);
4195
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004196 uint32_t index;
4197 const bool key_is_array_index = key->AsArrayIndex(&index);
4198
ager@chromium.org9085a012009-05-11 19:22:57 +00004199 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004200 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004201 if (obj->IsJSObject()) {
4202 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004203 // Fast case: either the key is a real named property or it is not
4204 // an array index and there are no interceptors or hidden
4205 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004206 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004207 Map* map = object->map();
4208 if (!key_is_array_index &&
4209 !map->has_named_interceptor() &&
4210 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4211 return isolate->heap()->false_value();
4212 }
4213 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004214 HandleScope scope(isolate);
4215 return HasLocalPropertyImplementation(isolate,
4216 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004217 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004218 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004219 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004220 String* string = String::cast(obj);
4221 if (index < static_cast<uint32_t>(string->length())) {
4222 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004223 }
4224 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004225 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004226}
4227
4228
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004229RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004230 NoHandleAllocation na;
4231 ASSERT(args.length() == 2);
4232
4233 // Only JS objects can have properties.
4234 if (args[0]->IsJSObject()) {
4235 JSObject* object = JSObject::cast(args[0]);
4236 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004237 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004238 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004239 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004240}
4241
4242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004243RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004244 NoHandleAllocation na;
4245 ASSERT(args.length() == 2);
4246
4247 // Only JS objects can have elements.
4248 if (args[0]->IsJSObject()) {
4249 JSObject* object = JSObject::cast(args[0]);
4250 CONVERT_CHECKED(Smi, index_obj, args[1]);
4251 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004252 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004253 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004254 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004255}
4256
4257
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004258RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004259 NoHandleAllocation ha;
4260 ASSERT(args.length() == 2);
4261
4262 CONVERT_CHECKED(JSObject, object, args[0]);
4263 CONVERT_CHECKED(String, key, args[1]);
4264
4265 uint32_t index;
4266 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004267 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004268 }
4269
ager@chromium.org870a0b62008-11-04 11:43:05 +00004270 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004271 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004272}
4273
4274
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004275RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004276 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004277 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004278 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004279 return *GetKeysFor(object);
4280}
4281
4282
4283// Returns either a FixedArray as Runtime_GetPropertyNames,
4284// or, if the given object has an enum cache that contains
4285// all enumerable properties of the object and its prototypes
4286// have none, the map of the object. This is used to speed up
4287// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004288RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004289 ASSERT(args.length() == 1);
4290
4291 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4292
4293 if (raw_object->IsSimpleEnum()) return raw_object->map();
4294
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004295 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004296 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004297 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4298 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004299
4300 // Test again, since cache may have been built by preceding call.
4301 if (object->IsSimpleEnum()) return object->map();
4302
4303 return *content;
4304}
4305
4306
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004307// Find the length of the prototype chain that is to to handled as one. If a
4308// prototype object is hidden it is to be viewed as part of the the object it
4309// is prototype for.
4310static int LocalPrototypeChainLength(JSObject* obj) {
4311 int count = 1;
4312 Object* proto = obj->GetPrototype();
4313 while (proto->IsJSObject() &&
4314 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4315 count++;
4316 proto = JSObject::cast(proto)->GetPrototype();
4317 }
4318 return count;
4319}
4320
4321
4322// Return the names of the local named properties.
4323// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004324RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004325 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004326 ASSERT(args.length() == 1);
4327 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004328 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004329 }
4330 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4331
4332 // Skip the global proxy as it has no properties and always delegates to the
4333 // real global object.
4334 if (obj->IsJSGlobalProxy()) {
4335 // Only collect names if access is permitted.
4336 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004337 !isolate->MayNamedAccess(*obj,
4338 isolate->heap()->undefined_value(),
4339 v8::ACCESS_KEYS)) {
4340 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4341 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004342 }
4343 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4344 }
4345
4346 // Find the number of objects making up this.
4347 int length = LocalPrototypeChainLength(*obj);
4348
4349 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004350 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004351 int total_property_count = 0;
4352 Handle<JSObject> jsproto = obj;
4353 for (int i = 0; i < length; i++) {
4354 // Only collect names if access is permitted.
4355 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004356 !isolate->MayNamedAccess(*jsproto,
4357 isolate->heap()->undefined_value(),
4358 v8::ACCESS_KEYS)) {
4359 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4360 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004361 }
4362 int n;
4363 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4364 local_property_count[i] = n;
4365 total_property_count += n;
4366 if (i < length - 1) {
4367 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4368 }
4369 }
4370
4371 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004372 Handle<FixedArray> names =
4373 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004374
4375 // Get the property names.
4376 jsproto = obj;
4377 int proto_with_hidden_properties = 0;
4378 for (int i = 0; i < length; i++) {
4379 jsproto->GetLocalPropertyNames(*names,
4380 i == 0 ? 0 : local_property_count[i - 1]);
4381 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4382 proto_with_hidden_properties++;
4383 }
4384 if (i < length - 1) {
4385 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4386 }
4387 }
4388
4389 // Filter out name of hidden propeties object.
4390 if (proto_with_hidden_properties > 0) {
4391 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004392 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004393 names->length() - proto_with_hidden_properties);
4394 int dest_pos = 0;
4395 for (int i = 0; i < total_property_count; i++) {
4396 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004397 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004398 continue;
4399 }
4400 names->set(dest_pos++, name);
4401 }
4402 }
4403
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004404 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004405}
4406
4407
4408// Return the names of the local indexed properties.
4409// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004410RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004411 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004412 ASSERT(args.length() == 1);
4413 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004414 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004415 }
4416 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4417
4418 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004419 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004420 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004421 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004422}
4423
4424
4425// Return information on whether an object has a named or indexed interceptor.
4426// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004427RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004428 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004429 ASSERT(args.length() == 1);
4430 if (!args[0]->IsJSObject()) {
4431 return Smi::FromInt(0);
4432 }
4433 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4434
4435 int result = 0;
4436 if (obj->HasNamedInterceptor()) result |= 2;
4437 if (obj->HasIndexedInterceptor()) result |= 1;
4438
4439 return Smi::FromInt(result);
4440}
4441
4442
4443// Return property names from named interceptor.
4444// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004445RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004446 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004447 ASSERT(args.length() == 1);
4448 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4449
4450 if (obj->HasNamedInterceptor()) {
4451 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4452 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4453 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004454 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004455}
4456
4457
4458// Return element names from indexed interceptor.
4459// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004460RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004461 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004462 ASSERT(args.length() == 1);
4463 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4464
4465 if (obj->HasIndexedInterceptor()) {
4466 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4467 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4468 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004469 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004470}
4471
4472
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004473RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004474 ASSERT_EQ(args.length(), 1);
4475 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004476 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004477 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004478
4479 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004480 // Do access checks before going to the global object.
4481 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004482 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004483 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004484 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4485 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004486 }
4487
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004488 Handle<Object> proto(object->GetPrototype());
4489 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004490 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004491 object = Handle<JSObject>::cast(proto);
4492 }
4493
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004494 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4495 LOCAL_ONLY);
4496 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4497 // property array and since the result is mutable we have to create
4498 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004499 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004500 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004501 for (int i = 0; i < length; i++) {
4502 Object* entry = contents->get(i);
4503 if (entry->IsString()) {
4504 copy->set(i, entry);
4505 } else {
4506 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004507 HandleScope scope(isolate);
4508 Handle<Object> entry_handle(entry, isolate);
4509 Handle<Object> entry_str =
4510 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004511 copy->set(i, *entry_str);
4512 }
4513 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004514 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004515}
4516
4517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004518RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004519 NoHandleAllocation ha;
4520 ASSERT(args.length() == 1);
4521
4522 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004523 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004524 it.AdvanceToArgumentsFrame();
4525 JavaScriptFrame* frame = it.frame();
4526
4527 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004528 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004529
4530 // Try to convert the key to an index. If successful and within
4531 // index return the the argument from the frame.
4532 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004533 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004534 return frame->GetParameter(index);
4535 }
4536
4537 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004538 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004539 bool exception = false;
4540 Handle<Object> converted =
4541 Execution::ToString(args.at<Object>(0), &exception);
4542 if (exception) return Failure::Exception();
4543 Handle<String> key = Handle<String>::cast(converted);
4544
4545 // Try to convert the string key into an array index.
4546 if (key->AsArrayIndex(&index)) {
4547 if (index < n) {
4548 return frame->GetParameter(index);
4549 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004550 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004551 }
4552 }
4553
4554 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004555 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4556 if (key->Equals(isolate->heap()->callee_symbol())) {
4557 Object* function = frame->function();
4558 if (function->IsJSFunction() &&
4559 JSFunction::cast(function)->shared()->strict_mode()) {
4560 return isolate->Throw(*isolate->factory()->NewTypeError(
4561 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4562 }
4563 return function;
4564 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004565
4566 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004567 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004568}
4569
4570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004571RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004572 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004573
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004574 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004575 Handle<Object> object = args.at<Object>(0);
4576 if (object->IsJSObject()) {
4577 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004578 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004579 MaybeObject* ok = js_object->TransformToFastProperties(0);
4580 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004581 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004582 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004583 return *object;
4584}
4585
4586
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004587RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004588 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004589
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004590 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004591 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004592 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004593 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004594 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004595 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004596 return *object;
4597}
4598
4599
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004600RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004601 NoHandleAllocation ha;
4602 ASSERT(args.length() == 1);
4603
4604 return args[0]->ToBoolean();
4605}
4606
4607
4608// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4609// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004610RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004611 NoHandleAllocation ha;
4612
4613 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004614 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004615 HeapObject* heap_obj = HeapObject::cast(obj);
4616
4617 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004618 if (heap_obj->map()->is_undetectable()) {
4619 return isolate->heap()->undefined_symbol();
4620 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004621
4622 InstanceType instance_type = heap_obj->map()->instance_type();
4623 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004624 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004625 }
4626
4627 switch (instance_type) {
4628 case ODDBALL_TYPE:
4629 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004630 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004631 }
4632 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004633 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004634 }
4635 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004636 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004637 case JS_FUNCTION_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004638 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004639 default:
4640 // For any kind of object not handled above, the spec rule for
4641 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004642 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004643 }
4644}
4645
4646
lrn@chromium.org25156de2010-04-06 13:10:27 +00004647static bool AreDigits(const char*s, int from, int to) {
4648 for (int i = from; i < to; i++) {
4649 if (s[i] < '0' || s[i] > '9') return false;
4650 }
4651
4652 return true;
4653}
4654
4655
4656static int ParseDecimalInteger(const char*s, int from, int to) {
4657 ASSERT(to - from < 10); // Overflow is not possible.
4658 ASSERT(from < to);
4659 int d = s[from] - '0';
4660
4661 for (int i = from + 1; i < to; i++) {
4662 d = 10 * d + (s[i] - '0');
4663 }
4664
4665 return d;
4666}
4667
4668
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004669RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004670 NoHandleAllocation ha;
4671 ASSERT(args.length() == 1);
4672 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004673 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004674
4675 // Fast case: short integer or some sorts of junk values.
4676 int len = subject->length();
4677 if (subject->IsSeqAsciiString()) {
4678 if (len == 0) return Smi::FromInt(0);
4679
4680 char const* data = SeqAsciiString::cast(subject)->GetChars();
4681 bool minus = (data[0] == '-');
4682 int start_pos = (minus ? 1 : 0);
4683
4684 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004685 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004686 } else if (data[start_pos] > '9') {
4687 // Fast check for a junk value. A valid string may start from a
4688 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4689 // the 'I' character ('Infinity'). All of that have codes not greater than
4690 // '9' except 'I'.
4691 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004692 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004693 }
4694 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4695 // The maximal/minimal smi has 10 digits. If the string has less digits we
4696 // know it will fit into the smi-data type.
4697 int d = ParseDecimalInteger(data, start_pos, len);
4698 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004699 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004700 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004701 } else if (!subject->HasHashCode() &&
4702 len <= String::kMaxArrayIndexSize &&
4703 (len == 1 || data[0] != '0')) {
4704 // String hash is not calculated yet but all the data are present.
4705 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004706 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004707#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004708 subject->Hash(); // Force hash calculation.
4709 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4710 static_cast<int>(hash));
4711#endif
4712 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004713 }
4714 return Smi::FromInt(d);
4715 }
4716 }
4717
4718 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004719 return isolate->heap()->NumberFromDouble(
4720 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004721}
4722
4723
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004724RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004725 NoHandleAllocation ha;
4726 ASSERT(args.length() == 1);
4727
4728 CONVERT_CHECKED(JSArray, codes, args[0]);
4729 int length = Smi::cast(codes->length())->value();
4730
4731 // Check if the string can be ASCII.
4732 int i;
4733 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004734 Object* element;
4735 { MaybeObject* maybe_element = codes->GetElement(i);
4736 // We probably can't get an exception here, but just in order to enforce
4737 // the checking of inputs in the runtime calls we check here.
4738 if (!maybe_element->ToObject(&element)) return maybe_element;
4739 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004740 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4741 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4742 break;
4743 }
4744
lrn@chromium.org303ada72010-10-27 09:33:13 +00004745 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004746 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004747 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004748 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004749 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004750 }
4751
lrn@chromium.org303ada72010-10-27 09:33:13 +00004752 Object* object = NULL;
4753 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004754 String* result = String::cast(object);
4755 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004756 Object* element;
4757 { MaybeObject* maybe_element = codes->GetElement(i);
4758 if (!maybe_element->ToObject(&element)) return maybe_element;
4759 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004760 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004761 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004762 }
4763 return result;
4764}
4765
4766
4767// kNotEscaped is generated by the following:
4768//
4769// #!/bin/perl
4770// for (my $i = 0; $i < 256; $i++) {
4771// print "\n" if $i % 16 == 0;
4772// my $c = chr($i);
4773// my $escaped = 1;
4774// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4775// print $escaped ? "0, " : "1, ";
4776// }
4777
4778
4779static bool IsNotEscaped(uint16_t character) {
4780 // Only for 8 bit characters, the rest are always escaped (in a different way)
4781 ASSERT(character < 256);
4782 static const char kNotEscaped[256] = {
4783 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4784 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4785 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4786 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4787 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4788 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4789 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4790 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4791 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4792 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4793 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4794 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4795 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4796 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4797 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4798 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4799 };
4800 return kNotEscaped[character] != 0;
4801}
4802
4803
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004804RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004805 const char hex_chars[] = "0123456789ABCDEF";
4806 NoHandleAllocation ha;
4807 ASSERT(args.length() == 1);
4808 CONVERT_CHECKED(String, source, args[0]);
4809
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004810 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004811
4812 int escaped_length = 0;
4813 int length = source->length();
4814 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004815 Access<StringInputBuffer> buffer(
4816 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004817 buffer->Reset(source);
4818 while (buffer->has_more()) {
4819 uint16_t character = buffer->GetNext();
4820 if (character >= 256) {
4821 escaped_length += 6;
4822 } else if (IsNotEscaped(character)) {
4823 escaped_length++;
4824 } else {
4825 escaped_length += 3;
4826 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004827 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004828 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004829 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004830 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004831 return Failure::OutOfMemoryException();
4832 }
4833 }
4834 }
4835 // No length change implies no change. Return original string if no change.
4836 if (escaped_length == length) {
4837 return source;
4838 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004839 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004840 { MaybeObject* maybe_o =
4841 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004842 if (!maybe_o->ToObject(&o)) return maybe_o;
4843 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004844 String* destination = String::cast(o);
4845 int dest_position = 0;
4846
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004847 Access<StringInputBuffer> buffer(
4848 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004849 buffer->Rewind();
4850 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004851 uint16_t chr = buffer->GetNext();
4852 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004853 destination->Set(dest_position, '%');
4854 destination->Set(dest_position+1, 'u');
4855 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4856 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4857 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4858 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004859 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004860 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004861 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004862 dest_position++;
4863 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004864 destination->Set(dest_position, '%');
4865 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4866 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004867 dest_position += 3;
4868 }
4869 }
4870 return destination;
4871}
4872
4873
4874static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4875 static const signed char kHexValue['g'] = {
4876 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4877 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4878 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4879 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4880 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4881 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4882 -1, 10, 11, 12, 13, 14, 15 };
4883
4884 if (character1 > 'f') return -1;
4885 int hi = kHexValue[character1];
4886 if (hi == -1) return -1;
4887 if (character2 > 'f') return -1;
4888 int lo = kHexValue[character2];
4889 if (lo == -1) return -1;
4890 return (hi << 4) + lo;
4891}
4892
4893
ager@chromium.org870a0b62008-11-04 11:43:05 +00004894static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004895 int i,
4896 int length,
4897 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004898 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004899 int32_t hi = 0;
4900 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004901 if (character == '%' &&
4902 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004903 source->Get(i + 1) == 'u' &&
4904 (hi = TwoDigitHex(source->Get(i + 2),
4905 source->Get(i + 3))) != -1 &&
4906 (lo = TwoDigitHex(source->Get(i + 4),
4907 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004908 *step = 6;
4909 return (hi << 8) + lo;
4910 } else if (character == '%' &&
4911 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004912 (lo = TwoDigitHex(source->Get(i + 1),
4913 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004914 *step = 3;
4915 return lo;
4916 } else {
4917 *step = 1;
4918 return character;
4919 }
4920}
4921
4922
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004923RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004924 NoHandleAllocation ha;
4925 ASSERT(args.length() == 1);
4926 CONVERT_CHECKED(String, source, args[0]);
4927
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004928 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004929
4930 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004931 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004932
4933 int unescaped_length = 0;
4934 for (int i = 0; i < length; unescaped_length++) {
4935 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004936 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004937 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004938 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004939 i += step;
4940 }
4941
4942 // No length change implies no change. Return original string if no change.
4943 if (unescaped_length == length)
4944 return source;
4945
lrn@chromium.org303ada72010-10-27 09:33:13 +00004946 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004947 { MaybeObject* maybe_o =
4948 ascii ?
4949 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
4950 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004951 if (!maybe_o->ToObject(&o)) return maybe_o;
4952 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004953 String* destination = String::cast(o);
4954
4955 int dest_position = 0;
4956 for (int i = 0; i < length; dest_position++) {
4957 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004958 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004959 i += step;
4960 }
4961 return destination;
4962}
4963
4964
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004965static const unsigned int kQuoteTableLength = 128u;
4966
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004967static const int kJsonQuotesCharactersPerEntry = 8;
4968static const char* const JsonQuotes =
4969 "\\u0000 \\u0001 \\u0002 \\u0003 "
4970 "\\u0004 \\u0005 \\u0006 \\u0007 "
4971 "\\b \\t \\n \\u000b "
4972 "\\f \\r \\u000e \\u000f "
4973 "\\u0010 \\u0011 \\u0012 \\u0013 "
4974 "\\u0014 \\u0015 \\u0016 \\u0017 "
4975 "\\u0018 \\u0019 \\u001a \\u001b "
4976 "\\u001c \\u001d \\u001e \\u001f "
4977 " ! \\\" # "
4978 "$ % & ' "
4979 "( ) * + "
4980 ", - . / "
4981 "0 1 2 3 "
4982 "4 5 6 7 "
4983 "8 9 : ; "
4984 "< = > ? "
4985 "@ A B C "
4986 "D E F G "
4987 "H I J K "
4988 "L M N O "
4989 "P Q R S "
4990 "T U V W "
4991 "X Y Z [ "
4992 "\\\\ ] ^ _ "
4993 "` a b c "
4994 "d e f g "
4995 "h i j k "
4996 "l m n o "
4997 "p q r s "
4998 "t u v w "
4999 "x y z { "
5000 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005001
5002
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005003// For a string that is less than 32k characters it should always be
5004// possible to allocate it in new space.
5005static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5006
5007
5008// Doing JSON quoting cannot make the string more than this many times larger.
5009static const int kJsonQuoteWorstCaseBlowup = 6;
5010
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005011static const int kSpaceForQuotesAndComma = 3;
5012static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005013
5014// Covers the entire ASCII range (all other characters are unchanged by JSON
5015// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005016static const byte JsonQuoteLengths[kQuoteTableLength] = {
5017 6, 6, 6, 6, 6, 6, 6, 6,
5018 2, 2, 2, 6, 2, 2, 6, 6,
5019 6, 6, 6, 6, 6, 6, 6, 6,
5020 6, 6, 6, 6, 6, 6, 6, 6,
5021 1, 1, 2, 1, 1, 1, 1, 1,
5022 1, 1, 1, 1, 1, 1, 1, 1,
5023 1, 1, 1, 1, 1, 1, 1, 1,
5024 1, 1, 1, 1, 1, 1, 1, 1,
5025 1, 1, 1, 1, 1, 1, 1, 1,
5026 1, 1, 1, 1, 1, 1, 1, 1,
5027 1, 1, 1, 1, 1, 1, 1, 1,
5028 1, 1, 1, 1, 2, 1, 1, 1,
5029 1, 1, 1, 1, 1, 1, 1, 1,
5030 1, 1, 1, 1, 1, 1, 1, 1,
5031 1, 1, 1, 1, 1, 1, 1, 1,
5032 1, 1, 1, 1, 1, 1, 1, 1,
5033};
5034
5035
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005036template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005037MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005038
5039
5040template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005041MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5042 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005043}
5044
5045
5046template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005047MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5048 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005049}
5050
5051
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005052template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005053static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5054 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005055 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005056 const Char* read_cursor = characters.start();
5057 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005058 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005059 int quoted_length = kSpaceForQuotes;
5060 while (read_cursor < end) {
5061 Char c = *(read_cursor++);
5062 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5063 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005064 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005065 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005066 }
5067 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005068 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5069 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005070 Object* new_object;
5071 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005072 return new_alloc;
5073 }
5074 StringType* new_string = StringType::cast(new_object);
5075
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005076 Char* write_cursor = reinterpret_cast<Char*>(
5077 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005078 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005079 *(write_cursor++) = '"';
5080
5081 read_cursor = characters.start();
5082 while (read_cursor < end) {
5083 Char c = *(read_cursor++);
5084 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5085 *(write_cursor++) = c;
5086 } else {
5087 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5088 const char* replacement = JsonQuotes +
5089 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5090 for (int i = 0; i < len; i++) {
5091 *write_cursor++ = *replacement++;
5092 }
5093 }
5094 }
5095 *(write_cursor++) = '"';
5096 return new_string;
5097}
5098
5099
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005100template <typename SinkChar, typename SourceChar>
5101static inline SinkChar* WriteQuoteJsonString(
5102 Isolate* isolate,
5103 SinkChar* write_cursor,
5104 Vector<const SourceChar> characters) {
5105 const SourceChar* read_cursor = characters.start();
5106 const SourceChar* end = read_cursor + characters.length();
5107 *(write_cursor++) = '"';
5108 while (read_cursor < end) {
5109 SourceChar c = *(read_cursor++);
5110 if (sizeof(SourceChar) > 1u &&
5111 static_cast<unsigned>(c) >= kQuoteTableLength) {
5112 *(write_cursor++) = static_cast<SinkChar>(c);
5113 } else {
5114 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5115 const char* replacement = JsonQuotes +
5116 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5117 write_cursor[0] = replacement[0];
5118 if (len > 1) {
5119 write_cursor[1] = replacement[1];
5120 if (len > 2) {
5121 ASSERT(len == 6);
5122 write_cursor[2] = replacement[2];
5123 write_cursor[3] = replacement[3];
5124 write_cursor[4] = replacement[4];
5125 write_cursor[5] = replacement[5];
5126 }
5127 }
5128 write_cursor += len;
5129 }
5130 }
5131 *(write_cursor++) = '"';
5132 return write_cursor;
5133}
5134
5135
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005136template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005137static MaybeObject* QuoteJsonString(Isolate* isolate,
5138 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005139 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005140 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005141 int worst_case_length =
5142 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005143 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005144 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005145 }
5146
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005147 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5148 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005149 Object* new_object;
5150 if (!new_alloc->ToObject(&new_object)) {
5151 return new_alloc;
5152 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005153 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005154 // Even if our string is small enough to fit in new space we still have to
5155 // handle it being allocated in old space as may happen in the third
5156 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5157 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005158 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005159 }
5160 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005161 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005162
5163 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5164 Char* write_cursor = reinterpret_cast<Char*>(
5165 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005166 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005167 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5168 write_cursor,
5169 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005170 int final_length = static_cast<int>(
5171 write_cursor - reinterpret_cast<Char*>(
5172 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005173 isolate->heap()->new_space()->
5174 template ShrinkStringAtAllocationBoundary<StringType>(
5175 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005176 return new_string;
5177}
5178
5179
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005180RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005181 NoHandleAllocation ha;
5182 CONVERT_CHECKED(String, str, args[0]);
5183 if (!str->IsFlat()) {
5184 MaybeObject* try_flatten = str->TryFlatten();
5185 Object* flat;
5186 if (!try_flatten->ToObject(&flat)) {
5187 return try_flatten;
5188 }
5189 str = String::cast(flat);
5190 ASSERT(str->IsFlat());
5191 }
5192 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005193 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5194 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005195 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005196 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5197 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005198 }
5199}
5200
5201
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005202RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005203 NoHandleAllocation ha;
5204 CONVERT_CHECKED(String, str, args[0]);
5205 if (!str->IsFlat()) {
5206 MaybeObject* try_flatten = str->TryFlatten();
5207 Object* flat;
5208 if (!try_flatten->ToObject(&flat)) {
5209 return try_flatten;
5210 }
5211 str = String::cast(flat);
5212 ASSERT(str->IsFlat());
5213 }
5214 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005215 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5216 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005217 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005218 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5219 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005220 }
5221}
5222
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005223
5224template <typename Char, typename StringType>
5225static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5226 FixedArray* array,
5227 int worst_case_length) {
5228 int length = array->length();
5229
5230 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5231 worst_case_length);
5232 Object* new_object;
5233 if (!new_alloc->ToObject(&new_object)) {
5234 return new_alloc;
5235 }
5236 if (!isolate->heap()->new_space()->Contains(new_object)) {
5237 // Even if our string is small enough to fit in new space we still have to
5238 // handle it being allocated in old space as may happen in the third
5239 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5240 // CEntryStub::GenerateCore.
5241 return isolate->heap()->undefined_value();
5242 }
5243 AssertNoAllocation no_gc;
5244 StringType* new_string = StringType::cast(new_object);
5245 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5246
5247 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5248 Char* write_cursor = reinterpret_cast<Char*>(
5249 new_string->address() + SeqAsciiString::kHeaderSize);
5250 *(write_cursor++) = '[';
5251 for (int i = 0; i < length; i++) {
5252 if (i != 0) *(write_cursor++) = ',';
5253 String* str = String::cast(array->get(i));
5254 if (str->IsTwoByteRepresentation()) {
5255 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5256 write_cursor,
5257 str->ToUC16Vector());
5258 } else {
5259 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5260 write_cursor,
5261 str->ToAsciiVector());
5262 }
5263 }
5264 *(write_cursor++) = ']';
5265
5266 int final_length = static_cast<int>(
5267 write_cursor - reinterpret_cast<Char*>(
5268 new_string->address() + SeqAsciiString::kHeaderSize));
5269 isolate->heap()->new_space()->
5270 template ShrinkStringAtAllocationBoundary<StringType>(
5271 new_string, final_length);
5272 return new_string;
5273}
5274
5275
5276RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5277 NoHandleAllocation ha;
5278 ASSERT(args.length() == 1);
5279 CONVERT_CHECKED(JSArray, array, args[0]);
5280
5281 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5282 FixedArray* elements = FixedArray::cast(array->elements());
5283 int n = elements->length();
5284 bool ascii = true;
5285 int total_length = 0;
5286
5287 for (int i = 0; i < n; i++) {
5288 Object* elt = elements->get(i);
5289 if (!elt->IsString()) return isolate->heap()->undefined_value();
5290 String* element = String::cast(elt);
5291 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5292 total_length += element->length();
5293 if (ascii && element->IsTwoByteRepresentation()) {
5294 ascii = false;
5295 }
5296 }
5297
5298 int worst_case_length =
5299 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5300 + total_length * kJsonQuoteWorstCaseBlowup;
5301
5302 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5303 return isolate->heap()->undefined_value();
5304 }
5305
5306 if (ascii) {
5307 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5308 elements,
5309 worst_case_length);
5310 } else {
5311 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5312 elements,
5313 worst_case_length);
5314 }
5315}
5316
5317
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005318RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005319 NoHandleAllocation ha;
5320
5321 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005322 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005323
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005324 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005325
lrn@chromium.org25156de2010-04-06 13:10:27 +00005326 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005327 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005328 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005329}
5330
5331
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005332RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005333 NoHandleAllocation ha;
5334 CONVERT_CHECKED(String, str, args[0]);
5335
5336 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005337 double value = StringToDouble(isolate->unicode_cache(),
5338 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005339
5340 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005341 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005342}
5343
5344
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005345template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005346MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005347 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005348 String* s,
5349 int length,
5350 int input_string_length,
5351 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005352 // We try this twice, once with the assumption that the result is no longer
5353 // than the input and, if that assumption breaks, again with the exact
5354 // length. This may not be pretty, but it is nicer than what was here before
5355 // and I hereby claim my vaffel-is.
5356 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005357 // Allocate the resulting string.
5358 //
5359 // NOTE: This assumes that the upper/lower case of an ascii
5360 // character is also ascii. This is currently the case, but it
5361 // might break in the future if we implement more context and locale
5362 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005363 Object* o;
5364 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005365 ? isolate->heap()->AllocateRawAsciiString(length)
5366 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005367 if (!maybe_o->ToObject(&o)) return maybe_o;
5368 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005369 String* result = String::cast(o);
5370 bool has_changed_character = false;
5371
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005372 // Convert all characters to upper case, assuming that they will fit
5373 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005374 Access<StringInputBuffer> buffer(
5375 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005376 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005377 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005378 // We can assume that the string is not empty
5379 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005380 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005381 bool has_next = buffer->has_more();
5382 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005383 int char_length = mapping->get(current, next, chars);
5384 if (char_length == 0) {
5385 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005386 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005387 i++;
5388 } else if (char_length == 1) {
5389 // Common case: converting the letter resulted in one character.
5390 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005391 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005392 has_changed_character = true;
5393 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005394 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005395 // We've assumed that the result would be as long as the
5396 // input but here is a character that converts to several
5397 // characters. No matter, we calculate the exact length
5398 // of the result and try the whole thing again.
5399 //
5400 // Note that this leaves room for optimization. We could just
5401 // memcpy what we already have to the result string. Also,
5402 // the result string is the last object allocated we could
5403 // "realloc" it and probably, in the vast majority of cases,
5404 // extend the existing string to be able to hold the full
5405 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005406 int next_length = 0;
5407 if (has_next) {
5408 next_length = mapping->get(next, 0, chars);
5409 if (next_length == 0) next_length = 1;
5410 }
5411 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005412 while (buffer->has_more()) {
5413 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005414 // NOTE: we use 0 as the next character here because, while
5415 // the next character may affect what a character converts to,
5416 // it does not in any case affect the length of what it convert
5417 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005418 int char_length = mapping->get(current, 0, chars);
5419 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005420 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005421 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005422 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005423 return Failure::OutOfMemoryException();
5424 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005425 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005426 // Try again with the real length.
5427 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005428 } else {
5429 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005430 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005431 i++;
5432 }
5433 has_changed_character = true;
5434 }
5435 current = next;
5436 }
5437 if (has_changed_character) {
5438 return result;
5439 } else {
5440 // If we didn't actually change anything in doing the conversion
5441 // we simple return the result and let the converted string
5442 // become garbage; there is no reason to keep two identical strings
5443 // alive.
5444 return s;
5445 }
5446}
5447
5448
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005449namespace {
5450
lrn@chromium.org303ada72010-10-27 09:33:13 +00005451static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5452
5453
5454// Given a word and two range boundaries returns a word with high bit
5455// set in every byte iff the corresponding input byte was strictly in
5456// the range (m, n). All the other bits in the result are cleared.
5457// This function is only useful when it can be inlined and the
5458// boundaries are statically known.
5459// Requires: all bytes in the input word and the boundaries must be
5460// ascii (less than 0x7F).
5461static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5462 // Every byte in an ascii string is less than or equal to 0x7F.
5463 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5464 // Use strict inequalities since in edge cases the function could be
5465 // further simplified.
5466 ASSERT(0 < m && m < n && n < 0x7F);
5467 // Has high bit set in every w byte less than n.
5468 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5469 // Has high bit set in every w byte greater than m.
5470 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5471 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5472}
5473
5474
5475enum AsciiCaseConversion {
5476 ASCII_TO_LOWER,
5477 ASCII_TO_UPPER
5478};
5479
5480
5481template <AsciiCaseConversion dir>
5482struct FastAsciiConverter {
5483 static bool Convert(char* dst, char* src, int length) {
5484#ifdef DEBUG
5485 char* saved_dst = dst;
5486 char* saved_src = src;
5487#endif
5488 // We rely on the distance between upper and lower case letters
5489 // being a known power of 2.
5490 ASSERT('a' - 'A' == (1 << 5));
5491 // Boundaries for the range of input characters than require conversion.
5492 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5493 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5494 bool changed = false;
5495 char* const limit = src + length;
5496#ifdef V8_HOST_CAN_READ_UNALIGNED
5497 // Process the prefix of the input that requires no conversion one
5498 // (machine) word at a time.
5499 while (src <= limit - sizeof(uintptr_t)) {
5500 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5501 if (AsciiRangeMask(w, lo, hi) != 0) {
5502 changed = true;
5503 break;
5504 }
5505 *reinterpret_cast<uintptr_t*>(dst) = w;
5506 src += sizeof(uintptr_t);
5507 dst += sizeof(uintptr_t);
5508 }
5509 // Process the remainder of the input performing conversion when
5510 // required one word at a time.
5511 while (src <= limit - sizeof(uintptr_t)) {
5512 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5513 uintptr_t m = AsciiRangeMask(w, lo, hi);
5514 // The mask has high (7th) bit set in every byte that needs
5515 // conversion and we know that the distance between cases is
5516 // 1 << 5.
5517 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5518 src += sizeof(uintptr_t);
5519 dst += sizeof(uintptr_t);
5520 }
5521#endif
5522 // Process the last few bytes of the input (or the whole input if
5523 // unaligned access is not supported).
5524 while (src < limit) {
5525 char c = *src;
5526 if (lo < c && c < hi) {
5527 c ^= (1 << 5);
5528 changed = true;
5529 }
5530 *dst = c;
5531 ++src;
5532 ++dst;
5533 }
5534#ifdef DEBUG
5535 CheckConvert(saved_dst, saved_src, length, changed);
5536#endif
5537 return changed;
5538 }
5539
5540#ifdef DEBUG
5541 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5542 bool expected_changed = false;
5543 for (int i = 0; i < length; i++) {
5544 if (dst[i] == src[i]) continue;
5545 expected_changed = true;
5546 if (dir == ASCII_TO_LOWER) {
5547 ASSERT('A' <= src[i] && src[i] <= 'Z');
5548 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5549 } else {
5550 ASSERT(dir == ASCII_TO_UPPER);
5551 ASSERT('a' <= src[i] && src[i] <= 'z');
5552 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5553 }
5554 }
5555 ASSERT(expected_changed == changed);
5556 }
5557#endif
5558};
5559
5560
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005561struct ToLowerTraits {
5562 typedef unibrow::ToLowercase UnibrowConverter;
5563
lrn@chromium.org303ada72010-10-27 09:33:13 +00005564 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005565};
5566
5567
5568struct ToUpperTraits {
5569 typedef unibrow::ToUppercase UnibrowConverter;
5570
lrn@chromium.org303ada72010-10-27 09:33:13 +00005571 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005572};
5573
5574} // namespace
5575
5576
5577template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005578MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005579 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005580 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005581 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005582 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005583 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005584 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005585
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005586 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005587 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005588 if (length == 0) return s;
5589
5590 // Simpler handling of ascii strings.
5591 //
5592 // NOTE: This assumes that the upper/lower case of an ascii
5593 // character is also ascii. This is currently the case, but it
5594 // might break in the future if we implement more context and locale
5595 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005596 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005597 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005598 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005599 if (!maybe_o->ToObject(&o)) return maybe_o;
5600 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005601 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005602 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005603 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005604 return has_changed_character ? result : s;
5605 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005606
lrn@chromium.org303ada72010-10-27 09:33:13 +00005607 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005608 { MaybeObject* maybe_answer =
5609 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005610 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5611 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005612 if (answer->IsSmi()) {
5613 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005614 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005615 ConvertCaseHelper(isolate,
5616 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005617 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5618 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005619 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005620 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005621}
5622
5623
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005624RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005625 return ConvertCase<ToLowerTraits>(
5626 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005627}
5628
5629
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005630RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005631 return ConvertCase<ToUpperTraits>(
5632 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005633}
5634
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005635
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005636static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5637 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5638}
5639
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005640
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005641RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005642 NoHandleAllocation ha;
5643 ASSERT(args.length() == 3);
5644
5645 CONVERT_CHECKED(String, s, args[0]);
5646 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5647 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5648
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005649 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005650 int length = s->length();
5651
5652 int left = 0;
5653 if (trimLeft) {
5654 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5655 left++;
5656 }
5657 }
5658
5659 int right = length;
5660 if (trimRight) {
5661 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5662 right--;
5663 }
5664 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005665 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005666}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005667
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005668
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005669template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005670void FindStringIndices(Isolate* isolate,
5671 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005672 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005673 ZoneList<int>* indices,
5674 unsigned int limit) {
5675 ASSERT(limit > 0);
5676 // Collect indices of pattern in subject, and the end-of-string index.
5677 // Stop after finding at most limit values.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005678 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005679 int pattern_length = pattern.length();
5680 int index = 0;
5681 while (limit > 0) {
5682 index = search.Search(subject, index);
5683 if (index < 0) return;
5684 indices->Add(index);
5685 index += pattern_length;
5686 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005687 }
5688}
5689
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005690
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005691RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005692 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005693 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005694 CONVERT_ARG_CHECKED(String, subject, 0);
5695 CONVERT_ARG_CHECKED(String, pattern, 1);
5696 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5697
5698 int subject_length = subject->length();
5699 int pattern_length = pattern->length();
5700 RUNTIME_ASSERT(pattern_length > 0);
5701
5702 // The limit can be very large (0xffffffffu), but since the pattern
5703 // isn't empty, we can never create more parts than ~half the length
5704 // of the subject.
5705
5706 if (!subject->IsFlat()) FlattenString(subject);
5707
5708 static const int kMaxInitialListCapacity = 16;
5709
danno@chromium.org40cb8782011-05-25 07:58:50 +00005710 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005711
5712 // Find (up to limit) indices of separator and end-of-string in subject
5713 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5714 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005715 if (!pattern->IsFlat()) FlattenString(pattern);
5716
5717 // No allocation block.
5718 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005719 AssertNoAllocation nogc;
5720 if (subject->IsAsciiRepresentation()) {
5721 Vector<const char> subject_vector = subject->ToAsciiVector();
5722 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005723 FindStringIndices(isolate,
5724 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005725 pattern->ToAsciiVector(),
5726 &indices,
5727 limit);
5728 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005729 FindStringIndices(isolate,
5730 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005731 pattern->ToUC16Vector(),
5732 &indices,
5733 limit);
5734 }
5735 } else {
5736 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5737 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005738 FindStringIndices(isolate,
5739 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005740 pattern->ToAsciiVector(),
5741 &indices,
5742 limit);
5743 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005744 FindStringIndices(isolate,
5745 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005746 pattern->ToUC16Vector(),
5747 &indices,
5748 limit);
5749 }
5750 }
5751 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005752
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005753 if (static_cast<uint32_t>(indices.length()) < limit) {
5754 indices.Add(subject_length);
5755 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005756
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005757 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005758
5759 // Create JSArray of substrings separated by separator.
5760 int part_count = indices.length();
5761
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005762 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005763 result->set_length(Smi::FromInt(part_count));
5764
5765 ASSERT(result->HasFastElements());
5766
5767 if (part_count == 1 && indices.at(0) == subject_length) {
5768 FixedArray::cast(result->elements())->set(0, *subject);
5769 return *result;
5770 }
5771
5772 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5773 int part_start = 0;
5774 for (int i = 0; i < part_count; i++) {
5775 HandleScope local_loop_handle;
5776 int part_end = indices.at(i);
5777 Handle<String> substring =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005778 isolate->factory()->NewSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005779 elements->set(i, *substring);
5780 part_start = part_end + pattern_length;
5781 }
5782
5783 return *result;
5784}
5785
5786
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005787// Copies ascii characters to the given fixed array looking up
5788// one-char strings in the cache. Gives up on the first char that is
5789// not in the cache and fills the remainder with smi zeros. Returns
5790// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005791static int CopyCachedAsciiCharsToArray(Heap* heap,
5792 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005793 FixedArray* elements,
5794 int length) {
5795 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005796 FixedArray* ascii_cache = heap->single_character_string_cache();
5797 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005798 int i;
5799 for (i = 0; i < length; ++i) {
5800 Object* value = ascii_cache->get(chars[i]);
5801 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005802 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005803 elements->set(i, value, SKIP_WRITE_BARRIER);
5804 }
5805 if (i < length) {
5806 ASSERT(Smi::FromInt(0) == 0);
5807 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5808 }
5809#ifdef DEBUG
5810 for (int j = 0; j < length; ++j) {
5811 Object* element = elements->get(j);
5812 ASSERT(element == Smi::FromInt(0) ||
5813 (element->IsString() && String::cast(element)->LooksValid()));
5814 }
5815#endif
5816 return i;
5817}
5818
5819
5820// Converts a String to JSArray.
5821// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005822RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005823 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005824 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005825 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005826 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005827
5828 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005829 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005830
5831 Handle<FixedArray> elements;
5832 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005833 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005834 { MaybeObject* maybe_obj =
5835 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005836 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5837 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005838 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005839
5840 Vector<const char> chars = s->ToAsciiVector();
5841 // Note, this will initialize all elements (not only the prefix)
5842 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005843 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5844 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005845 *elements,
5846 length);
5847
5848 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005849 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5850 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005851 }
5852 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005853 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005854 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005855 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5856 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005857 }
5858 }
5859
5860#ifdef DEBUG
5861 for (int i = 0; i < length; ++i) {
5862 ASSERT(String::cast(elements->get(i))->length() == 1);
5863 }
5864#endif
5865
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005866 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005867}
5868
5869
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005870RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005871 NoHandleAllocation ha;
5872 ASSERT(args.length() == 1);
5873 CONVERT_CHECKED(String, value, args[0]);
5874 return value->ToObject();
5875}
5876
5877
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005878bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005879 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005880 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005881 return char_length == 0;
5882}
5883
5884
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005885RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005886 NoHandleAllocation ha;
5887 ASSERT(args.length() == 1);
5888
5889 Object* number = args[0];
5890 RUNTIME_ASSERT(number->IsNumber());
5891
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005892 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005893}
5894
5895
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005896RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005897 NoHandleAllocation ha;
5898 ASSERT(args.length() == 1);
5899
5900 Object* number = args[0];
5901 RUNTIME_ASSERT(number->IsNumber());
5902
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005903 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00005904}
5905
5906
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005907RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005908 NoHandleAllocation ha;
5909 ASSERT(args.length() == 1);
5910
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005911 CONVERT_DOUBLE_CHECKED(number, args[0]);
5912
5913 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5914 if (number > 0 && number <= Smi::kMaxValue) {
5915 return Smi::FromInt(static_cast<int>(number));
5916 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005917 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005918}
5919
5920
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005921RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005922 NoHandleAllocation ha;
5923 ASSERT(args.length() == 1);
5924
5925 CONVERT_DOUBLE_CHECKED(number, args[0]);
5926
5927 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5928 if (number > 0 && number <= Smi::kMaxValue) {
5929 return Smi::FromInt(static_cast<int>(number));
5930 }
5931
5932 double double_value = DoubleToInteger(number);
5933 // Map both -0 and +0 to +0.
5934 if (double_value == 0) double_value = 0;
5935
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005936 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005937}
5938
5939
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005940RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005941 NoHandleAllocation ha;
5942 ASSERT(args.length() == 1);
5943
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005944 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005945 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005946}
5947
5948
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005949RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005950 NoHandleAllocation ha;
5951 ASSERT(args.length() == 1);
5952
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005953 CONVERT_DOUBLE_CHECKED(number, args[0]);
5954
5955 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5956 if (number > 0 && number <= Smi::kMaxValue) {
5957 return Smi::FromInt(static_cast<int>(number));
5958 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005959 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005960}
5961
5962
ager@chromium.org870a0b62008-11-04 11:43:05 +00005963// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5964// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005965RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005966 NoHandleAllocation ha;
5967 ASSERT(args.length() == 1);
5968
5969 Object* obj = args[0];
5970 if (obj->IsSmi()) {
5971 return obj;
5972 }
5973 if (obj->IsHeapNumber()) {
5974 double value = HeapNumber::cast(obj)->value();
5975 int int_value = FastD2I(value);
5976 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5977 return Smi::FromInt(int_value);
5978 }
5979 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005980 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00005981}
5982
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005983
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005984RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005985 NoHandleAllocation ha;
5986 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005987 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005988}
5989
5990
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005991RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005992 NoHandleAllocation ha;
5993 ASSERT(args.length() == 2);
5994
5995 CONVERT_DOUBLE_CHECKED(x, args[0]);
5996 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005997 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005998}
5999
6000
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006001RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006002 NoHandleAllocation ha;
6003 ASSERT(args.length() == 2);
6004
6005 CONVERT_DOUBLE_CHECKED(x, args[0]);
6006 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006007 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006008}
6009
6010
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006011RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006012 NoHandleAllocation ha;
6013 ASSERT(args.length() == 2);
6014
6015 CONVERT_DOUBLE_CHECKED(x, args[0]);
6016 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006017 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006018}
6019
6020
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006021RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006022 NoHandleAllocation ha;
6023 ASSERT(args.length() == 1);
6024
6025 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006026 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006027}
6028
6029
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006030RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006031 NoHandleAllocation ha;
6032 ASSERT(args.length() == 0);
6033
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006034 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006035}
6036
6037
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006038RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006039 NoHandleAllocation ha;
6040 ASSERT(args.length() == 2);
6041
6042 CONVERT_DOUBLE_CHECKED(x, args[0]);
6043 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006044 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006045}
6046
6047
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006048RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006049 NoHandleAllocation ha;
6050 ASSERT(args.length() == 2);
6051
6052 CONVERT_DOUBLE_CHECKED(x, args[0]);
6053 CONVERT_DOUBLE_CHECKED(y, args[1]);
6054
ager@chromium.org3811b432009-10-28 14:53:37 +00006055 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006056 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006057 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006058}
6059
6060
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006061RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006062 NoHandleAllocation ha;
6063 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006064 CONVERT_CHECKED(String, str1, args[0]);
6065 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006066 isolate->counters()->string_add_runtime()->Increment();
6067 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006068}
6069
6070
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006071template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006072static inline void StringBuilderConcatHelper(String* special,
6073 sinkchar* sink,
6074 FixedArray* fixed_array,
6075 int array_length) {
6076 int position = 0;
6077 for (int i = 0; i < array_length; i++) {
6078 Object* element = fixed_array->get(i);
6079 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006080 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006081 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006082 int pos;
6083 int len;
6084 if (encoded_slice > 0) {
6085 // Position and length encoded in one smi.
6086 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6087 len = StringBuilderSubstringLength::decode(encoded_slice);
6088 } else {
6089 // Position and length encoded in two smis.
6090 Object* obj = fixed_array->get(++i);
6091 ASSERT(obj->IsSmi());
6092 pos = Smi::cast(obj)->value();
6093 len = -encoded_slice;
6094 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006095 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006096 sink + position,
6097 pos,
6098 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006099 position += len;
6100 } else {
6101 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006102 int element_length = string->length();
6103 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006104 position += element_length;
6105 }
6106 }
6107}
6108
6109
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006110RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006111 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006112 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006113 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006114 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006115 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006116 return Failure::OutOfMemoryException();
6117 }
6118 int array_length = Smi::cast(args[1])->value();
6119 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006120
6121 // This assumption is used by the slice encoding in one or two smis.
6122 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6123
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006124 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006125 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006126 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006127 }
6128 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006129 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006130 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006131 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006132
6133 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006134 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006135 } else if (array_length == 1) {
6136 Object* first = fixed_array->get(0);
6137 if (first->IsString()) return first;
6138 }
6139
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006140 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006141 int position = 0;
6142 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006143 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006144 Object* elt = fixed_array->get(i);
6145 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006146 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006147 int smi_value = Smi::cast(elt)->value();
6148 int pos;
6149 int len;
6150 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006151 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006152 pos = StringBuilderSubstringPosition::decode(smi_value);
6153 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006154 } else {
6155 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006156 len = -smi_value;
6157 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006158 i++;
6159 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006160 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006161 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006162 Object* next_smi = fixed_array->get(i);
6163 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006164 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006165 }
6166 pos = Smi::cast(next_smi)->value();
6167 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006168 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006169 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006170 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006171 ASSERT(pos >= 0);
6172 ASSERT(len >= 0);
6173 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006174 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006175 }
6176 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006177 } else if (elt->IsString()) {
6178 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006179 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006180 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006181 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006182 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006183 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006184 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006185 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006186 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006187 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006188 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006189 return Failure::OutOfMemoryException();
6190 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006191 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006192 }
6193
6194 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006195 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006196
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006197 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006198 { MaybeObject* maybe_object =
6199 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006200 if (!maybe_object->ToObject(&object)) return maybe_object;
6201 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006202 SeqAsciiString* answer = SeqAsciiString::cast(object);
6203 StringBuilderConcatHelper(special,
6204 answer->GetChars(),
6205 fixed_array,
6206 array_length);
6207 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006208 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006209 { MaybeObject* maybe_object =
6210 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006211 if (!maybe_object->ToObject(&object)) return maybe_object;
6212 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006213 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6214 StringBuilderConcatHelper(special,
6215 answer->GetChars(),
6216 fixed_array,
6217 array_length);
6218 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006219 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006220}
6221
6222
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006223RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006224 NoHandleAllocation ha;
6225 ASSERT(args.length() == 3);
6226 CONVERT_CHECKED(JSArray, array, args[0]);
6227 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006228 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006229 return Failure::OutOfMemoryException();
6230 }
6231 int array_length = Smi::cast(args[1])->value();
6232 CONVERT_CHECKED(String, separator, args[2]);
6233
6234 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006235 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006236 }
6237 FixedArray* fixed_array = FixedArray::cast(array->elements());
6238 if (fixed_array->length() < array_length) {
6239 array_length = fixed_array->length();
6240 }
6241
6242 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006243 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006244 } else if (array_length == 1) {
6245 Object* first = fixed_array->get(0);
6246 if (first->IsString()) return first;
6247 }
6248
6249 int separator_length = separator->length();
6250 int max_nof_separators =
6251 (String::kMaxLength + separator_length - 1) / separator_length;
6252 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006253 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006254 return Failure::OutOfMemoryException();
6255 }
6256 int length = (array_length - 1) * separator_length;
6257 for (int i = 0; i < array_length; i++) {
6258 Object* element_obj = fixed_array->get(i);
6259 if (!element_obj->IsString()) {
6260 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006261 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006262 }
6263 String* element = String::cast(element_obj);
6264 int increment = element->length();
6265 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006266 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006267 return Failure::OutOfMemoryException();
6268 }
6269 length += increment;
6270 }
6271
6272 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006273 { MaybeObject* maybe_object =
6274 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006275 if (!maybe_object->ToObject(&object)) return maybe_object;
6276 }
6277 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6278
6279 uc16* sink = answer->GetChars();
6280#ifdef DEBUG
6281 uc16* end = sink + length;
6282#endif
6283
6284 String* first = String::cast(fixed_array->get(0));
6285 int first_length = first->length();
6286 String::WriteToFlat(first, sink, 0, first_length);
6287 sink += first_length;
6288
6289 for (int i = 1; i < array_length; i++) {
6290 ASSERT(sink + separator_length <= end);
6291 String::WriteToFlat(separator, sink, 0, separator_length);
6292 sink += separator_length;
6293
6294 String* element = String::cast(fixed_array->get(i));
6295 int element_length = element->length();
6296 ASSERT(sink + element_length <= end);
6297 String::WriteToFlat(element, sink, 0, element_length);
6298 sink += element_length;
6299 }
6300 ASSERT(sink == end);
6301
6302 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6303 return answer;
6304}
6305
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006306template <typename Char>
6307static void JoinSparseArrayWithSeparator(FixedArray* elements,
6308 int elements_length,
6309 uint32_t array_length,
6310 String* separator,
6311 Vector<Char> buffer) {
6312 int previous_separator_position = 0;
6313 int separator_length = separator->length();
6314 int cursor = 0;
6315 for (int i = 0; i < elements_length; i += 2) {
6316 int position = NumberToInt32(elements->get(i));
6317 String* string = String::cast(elements->get(i + 1));
6318 int string_length = string->length();
6319 if (string->length() > 0) {
6320 while (previous_separator_position < position) {
6321 String::WriteToFlat<Char>(separator, &buffer[cursor],
6322 0, separator_length);
6323 cursor += separator_length;
6324 previous_separator_position++;
6325 }
6326 String::WriteToFlat<Char>(string, &buffer[cursor],
6327 0, string_length);
6328 cursor += string->length();
6329 }
6330 }
6331 if (separator_length > 0) {
6332 // Array length must be representable as a signed 32-bit number,
6333 // otherwise the total string length would have been too large.
6334 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6335 int last_array_index = static_cast<int>(array_length - 1);
6336 while (previous_separator_position < last_array_index) {
6337 String::WriteToFlat<Char>(separator, &buffer[cursor],
6338 0, separator_length);
6339 cursor += separator_length;
6340 previous_separator_position++;
6341 }
6342 }
6343 ASSERT(cursor <= buffer.length());
6344}
6345
6346
6347RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6348 NoHandleAllocation ha;
6349 ASSERT(args.length() == 3);
6350 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6351 RUNTIME_ASSERT(elements_array->HasFastElements());
6352 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6353 CONVERT_CHECKED(String, separator, args[2]);
6354 // elements_array is fast-mode JSarray of alternating positions
6355 // (increasing order) and strings.
6356 // array_length is length of original array (used to add separators);
6357 // separator is string to put between elements. Assumed to be non-empty.
6358
6359 // Find total length of join result.
6360 int string_length = 0;
6361 bool is_ascii = true;
6362 int max_string_length = SeqAsciiString::kMaxLength;
6363 bool overflow = false;
6364 CONVERT_NUMBER_CHECKED(int, elements_length,
6365 Int32, elements_array->length());
6366 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6367 FixedArray* elements = FixedArray::cast(elements_array->elements());
6368 for (int i = 0; i < elements_length; i += 2) {
6369 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6370 CONVERT_CHECKED(String, string, elements->get(i + 1));
6371 int length = string->length();
6372 if (is_ascii && !string->IsAsciiRepresentation()) {
6373 is_ascii = false;
6374 max_string_length = SeqTwoByteString::kMaxLength;
6375 }
6376 if (length > max_string_length ||
6377 max_string_length - length < string_length) {
6378 overflow = true;
6379 break;
6380 }
6381 string_length += length;
6382 }
6383 int separator_length = separator->length();
6384 if (!overflow && separator_length > 0) {
6385 if (array_length <= 0x7fffffffu) {
6386 int separator_count = static_cast<int>(array_length) - 1;
6387 int remaining_length = max_string_length - string_length;
6388 if ((remaining_length / separator_length) >= separator_count) {
6389 string_length += separator_length * (array_length - 1);
6390 } else {
6391 // Not room for the separators within the maximal string length.
6392 overflow = true;
6393 }
6394 } else {
6395 // Nonempty separator and at least 2^31-1 separators necessary
6396 // means that the string is too large to create.
6397 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6398 overflow = true;
6399 }
6400 }
6401 if (overflow) {
6402 // Throw OutOfMemory exception for creating too large a string.
6403 V8::FatalProcessOutOfMemory("Array join result too large.");
6404 }
6405
6406 if (is_ascii) {
6407 MaybeObject* result_allocation =
6408 isolate->heap()->AllocateRawAsciiString(string_length);
6409 if (result_allocation->IsFailure()) return result_allocation;
6410 SeqAsciiString* result_string =
6411 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6412 JoinSparseArrayWithSeparator<char>(elements,
6413 elements_length,
6414 array_length,
6415 separator,
6416 Vector<char>(result_string->GetChars(),
6417 string_length));
6418 return result_string;
6419 } else {
6420 MaybeObject* result_allocation =
6421 isolate->heap()->AllocateRawTwoByteString(string_length);
6422 if (result_allocation->IsFailure()) return result_allocation;
6423 SeqTwoByteString* result_string =
6424 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6425 JoinSparseArrayWithSeparator<uc16>(elements,
6426 elements_length,
6427 array_length,
6428 separator,
6429 Vector<uc16>(result_string->GetChars(),
6430 string_length));
6431 return result_string;
6432 }
6433}
6434
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006435
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006436RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006437 NoHandleAllocation ha;
6438 ASSERT(args.length() == 2);
6439
6440 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6441 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006442 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006443}
6444
6445
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006446RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006447 NoHandleAllocation ha;
6448 ASSERT(args.length() == 2);
6449
6450 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6451 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006452 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006453}
6454
6455
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006456RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006457 NoHandleAllocation ha;
6458 ASSERT(args.length() == 2);
6459
6460 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6461 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006462 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006463}
6464
6465
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006466RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006467 NoHandleAllocation ha;
6468 ASSERT(args.length() == 1);
6469
6470 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006471 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006472}
6473
6474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006475RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006476 NoHandleAllocation ha;
6477 ASSERT(args.length() == 2);
6478
6479 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6480 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006481 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006482}
6483
6484
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006485RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006486 NoHandleAllocation ha;
6487 ASSERT(args.length() == 2);
6488
6489 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6490 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006491 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006492}
6493
6494
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006495RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006496 NoHandleAllocation ha;
6497 ASSERT(args.length() == 2);
6498
6499 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6500 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006501 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006502}
6503
6504
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006505RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006506 NoHandleAllocation ha;
6507 ASSERT(args.length() == 2);
6508
6509 CONVERT_DOUBLE_CHECKED(x, args[0]);
6510 CONVERT_DOUBLE_CHECKED(y, args[1]);
6511 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6512 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6513 if (x == y) return Smi::FromInt(EQUAL);
6514 Object* result;
6515 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6516 result = Smi::FromInt(EQUAL);
6517 } else {
6518 result = Smi::FromInt(NOT_EQUAL);
6519 }
6520 return result;
6521}
6522
6523
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006524RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006525 NoHandleAllocation ha;
6526 ASSERT(args.length() == 2);
6527
6528 CONVERT_CHECKED(String, x, args[0]);
6529 CONVERT_CHECKED(String, y, args[1]);
6530
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006531 bool not_equal = !x->Equals(y);
6532 // This is slightly convoluted because the value that signifies
6533 // equality is 0 and inequality is 1 so we have to negate the result
6534 // from String::Equals.
6535 ASSERT(not_equal == 0 || not_equal == 1);
6536 STATIC_CHECK(EQUAL == 0);
6537 STATIC_CHECK(NOT_EQUAL == 1);
6538 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006539}
6540
6541
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006542RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006543 NoHandleAllocation ha;
6544 ASSERT(args.length() == 3);
6545
6546 CONVERT_DOUBLE_CHECKED(x, args[0]);
6547 CONVERT_DOUBLE_CHECKED(y, args[1]);
6548 if (isnan(x) || isnan(y)) return args[2];
6549 if (x == y) return Smi::FromInt(EQUAL);
6550 if (isless(x, y)) return Smi::FromInt(LESS);
6551 return Smi::FromInt(GREATER);
6552}
6553
6554
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006555// Compare two Smis as if they were converted to strings and then
6556// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006557RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006558 NoHandleAllocation ha;
6559 ASSERT(args.length() == 2);
6560
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006561 // Extract the integer values from the Smis.
6562 CONVERT_CHECKED(Smi, x, args[0]);
6563 CONVERT_CHECKED(Smi, y, args[1]);
6564 int x_value = x->value();
6565 int y_value = y->value();
6566
6567 // If the integers are equal so are the string representations.
6568 if (x_value == y_value) return Smi::FromInt(EQUAL);
6569
6570 // If one of the integers are zero the normal integer order is the
6571 // same as the lexicographic order of the string representations.
6572 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6573
ager@chromium.org32912102009-01-16 10:38:43 +00006574 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006575 // smallest because the char code of '-' is less than the char code
6576 // of any digit. Otherwise, we make both values positive.
6577 if (x_value < 0 || y_value < 0) {
6578 if (y_value >= 0) return Smi::FromInt(LESS);
6579 if (x_value >= 0) return Smi::FromInt(GREATER);
6580 x_value = -x_value;
6581 y_value = -y_value;
6582 }
6583
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006584 // Arrays for the individual characters of the two Smis. Smis are
6585 // 31 bit integers and 10 decimal digits are therefore enough.
6586 // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
6587 int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
6588 int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
6589
6590
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006591 // Convert the integers to arrays of their decimal digits.
6592 int x_index = 0;
6593 int y_index = 0;
6594 while (x_value > 0) {
6595 x_elms[x_index++] = x_value % 10;
6596 x_value /= 10;
6597 }
6598 while (y_value > 0) {
6599 y_elms[y_index++] = y_value % 10;
6600 y_value /= 10;
6601 }
6602
6603 // Loop through the arrays of decimal digits finding the first place
6604 // where they differ.
6605 while (--x_index >= 0 && --y_index >= 0) {
6606 int diff = x_elms[x_index] - y_elms[y_index];
6607 if (diff != 0) return Smi::FromInt(diff);
6608 }
6609
6610 // If one array is a suffix of the other array, the longest array is
6611 // the representation of the largest of the Smis in the
6612 // lexicographic ordering.
6613 return Smi::FromInt(x_index - y_index);
6614}
6615
6616
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006617static Object* StringInputBufferCompare(RuntimeState* state,
6618 String* x,
6619 String* y) {
6620 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6621 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006622 bufx.Reset(x);
6623 bufy.Reset(y);
6624 while (bufx.has_more() && bufy.has_more()) {
6625 int d = bufx.GetNext() - bufy.GetNext();
6626 if (d < 0) return Smi::FromInt(LESS);
6627 else if (d > 0) return Smi::FromInt(GREATER);
6628 }
6629
6630 // x is (non-trivial) prefix of y:
6631 if (bufy.has_more()) return Smi::FromInt(LESS);
6632 // y is prefix of x:
6633 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6634}
6635
6636
6637static Object* FlatStringCompare(String* x, String* y) {
6638 ASSERT(x->IsFlat());
6639 ASSERT(y->IsFlat());
6640 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6641 int prefix_length = x->length();
6642 if (y->length() < prefix_length) {
6643 prefix_length = y->length();
6644 equal_prefix_result = Smi::FromInt(GREATER);
6645 } else if (y->length() > prefix_length) {
6646 equal_prefix_result = Smi::FromInt(LESS);
6647 }
6648 int r;
6649 if (x->IsAsciiRepresentation()) {
6650 Vector<const char> x_chars = x->ToAsciiVector();
6651 if (y->IsAsciiRepresentation()) {
6652 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006653 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006654 } else {
6655 Vector<const uc16> y_chars = y->ToUC16Vector();
6656 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6657 }
6658 } else {
6659 Vector<const uc16> x_chars = x->ToUC16Vector();
6660 if (y->IsAsciiRepresentation()) {
6661 Vector<const char> y_chars = y->ToAsciiVector();
6662 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6663 } else {
6664 Vector<const uc16> y_chars = y->ToUC16Vector();
6665 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6666 }
6667 }
6668 Object* result;
6669 if (r == 0) {
6670 result = equal_prefix_result;
6671 } else {
6672 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6673 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006674 ASSERT(result ==
6675 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006676 return result;
6677}
6678
6679
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006680RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006681 NoHandleAllocation ha;
6682 ASSERT(args.length() == 2);
6683
6684 CONVERT_CHECKED(String, x, args[0]);
6685 CONVERT_CHECKED(String, y, args[1]);
6686
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006687 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006688
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006689 // A few fast case tests before we flatten.
6690 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006691 if (y->length() == 0) {
6692 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006693 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006694 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006695 return Smi::FromInt(LESS);
6696 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006697
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006698 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006699 if (d < 0) return Smi::FromInt(LESS);
6700 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006701
lrn@chromium.org303ada72010-10-27 09:33:13 +00006702 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006703 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006704 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6705 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006706 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006707 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6708 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006709
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006710 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006711 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006712}
6713
6714
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006715RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006716 NoHandleAllocation ha;
6717 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006718 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006719
6720 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006721 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006722}
6723
6724
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006725RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006726 NoHandleAllocation ha;
6727 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006728 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006729
6730 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006731 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006732}
6733
6734
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006735RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006736 NoHandleAllocation ha;
6737 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006738 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006739
6740 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006741 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006742}
6743
6744
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006745static const double kPiDividedBy4 = 0.78539816339744830962;
6746
6747
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006748RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006749 NoHandleAllocation ha;
6750 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006751 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006752
6753 CONVERT_DOUBLE_CHECKED(x, args[0]);
6754 CONVERT_DOUBLE_CHECKED(y, args[1]);
6755 double result;
6756 if (isinf(x) && isinf(y)) {
6757 // Make sure that the result in case of two infinite arguments
6758 // is a multiple of Pi / 4. The sign of the result is determined
6759 // by the first argument (x) and the sign of the second argument
6760 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006761 int multiplier = (x < 0) ? -1 : 1;
6762 if (y < 0) multiplier *= 3;
6763 result = multiplier * kPiDividedBy4;
6764 } else {
6765 result = atan2(x, y);
6766 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006767 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006768}
6769
6770
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006771RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006772 NoHandleAllocation ha;
6773 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006774 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006775
6776 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006777 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006778}
6779
6780
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006781RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006782 NoHandleAllocation ha;
6783 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006784 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006785
6786 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006787 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006788}
6789
6790
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006791RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006792 NoHandleAllocation ha;
6793 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006794 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006795
6796 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006797 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006798}
6799
6800
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006801RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006802 NoHandleAllocation ha;
6803 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006804 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006805
6806 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006807 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006808}
6809
6810
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006811RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
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_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006815
6816 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006817 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, 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_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006822 NoHandleAllocation ha;
6823 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006824 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006825
6826 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006827
6828 // If the second argument is a smi, it is much faster to call the
6829 // custom powi() function than the generic pow().
6830 if (args[1]->IsSmi()) {
6831 int y = Smi::cast(args[1])->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006832 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006833 }
6834
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006835 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006836 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006837}
6838
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006839// Fast version of Math.pow if we know that y is not an integer and
6840// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006841RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006842 NoHandleAllocation ha;
6843 ASSERT(args.length() == 2);
6844 CONVERT_DOUBLE_CHECKED(x, args[0]);
6845 CONVERT_DOUBLE_CHECKED(y, args[1]);
6846 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006847 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006848 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006849 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006850 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006851 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006852 }
6853}
6854
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006855
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006856RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006857 NoHandleAllocation ha;
6858 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006859 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006860
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006861 if (!args[0]->IsHeapNumber()) {
6862 // Must be smi. Return the argument unchanged for all the other types
6863 // to make fuzz-natives test happy.
6864 return args[0];
6865 }
6866
6867 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6868
6869 double value = number->value();
6870 int exponent = number->get_exponent();
6871 int sign = number->get_sign();
6872
danno@chromium.org160a7b02011-04-18 15:51:38 +00006873 if (exponent < -1) {
6874 // Number in range ]-0.5..0.5[. These always round to +/-zero.
6875 if (sign) return isolate->heap()->minus_zero_value();
6876 return Smi::FromInt(0);
6877 }
6878
6879 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
6880 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
6881 // agument holds for 32-bit smis).
6882 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006883 return Smi::FromInt(static_cast<int>(value + 0.5));
6884 }
6885
6886 // If the magnitude is big enough, there's no place for fraction part. If we
6887 // try to add 0.5 to this number, 1.0 will be added instead.
6888 if (exponent >= 52) {
6889 return number;
6890 }
6891
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006892 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006893
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006894 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006895 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006896}
6897
6898
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006899RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006900 NoHandleAllocation ha;
6901 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006902 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006903
6904 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006905 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006906}
6907
6908
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006909RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006910 NoHandleAllocation ha;
6911 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006912 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006913
6914 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006915 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006916}
6917
6918
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006919RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006920 NoHandleAllocation ha;
6921 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006922 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006923
6924 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006925 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006926}
6927
6928
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006929static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006930 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6931 181, 212, 243, 273, 304, 334};
6932 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6933 182, 213, 244, 274, 305, 335};
6934
6935 year += month / 12;
6936 month %= 12;
6937 if (month < 0) {
6938 year--;
6939 month += 12;
6940 }
6941
6942 ASSERT(month >= 0);
6943 ASSERT(month < 12);
6944
6945 // year_delta is an arbitrary number such that:
6946 // a) year_delta = -1 (mod 400)
6947 // b) year + year_delta > 0 for years in the range defined by
6948 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6949 // Jan 1 1970. This is required so that we don't run into integer
6950 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006951 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006952 // operations.
6953 static const int year_delta = 399999;
6954 static const int base_day = 365 * (1970 + year_delta) +
6955 (1970 + year_delta) / 4 -
6956 (1970 + year_delta) / 100 +
6957 (1970 + year_delta) / 400;
6958
6959 int year1 = year + year_delta;
6960 int day_from_year = 365 * year1 +
6961 year1 / 4 -
6962 year1 / 100 +
6963 year1 / 400 -
6964 base_day;
6965
6966 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006967 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006968 }
6969
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006970 return day_from_year + day_from_month_leap[month] + day - 1;
6971}
6972
6973
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006974RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006975 NoHandleAllocation ha;
6976 ASSERT(args.length() == 3);
6977
6978 CONVERT_SMI_CHECKED(year, args[0]);
6979 CONVERT_SMI_CHECKED(month, args[1]);
6980 CONVERT_SMI_CHECKED(date, args[2]);
6981
6982 return Smi::FromInt(MakeDay(year, month, date));
6983}
6984
6985
6986static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6987static const int kDaysIn4Years = 4 * 365 + 1;
6988static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6989static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6990static const int kDays1970to2000 = 30 * 365 + 7;
6991static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6992 kDays1970to2000;
6993static const int kYearsOffset = 400000;
6994
6995static const char kDayInYear[] = {
6996 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6997 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6998 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6999 22, 23, 24, 25, 26, 27, 28,
7000 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7001 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7002 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7003 22, 23, 24, 25, 26, 27, 28, 29, 30,
7004 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7005 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7006 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7007 22, 23, 24, 25, 26, 27, 28, 29, 30,
7008 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7009 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7010 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7011 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7012 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7013 22, 23, 24, 25, 26, 27, 28, 29, 30,
7014 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7015 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7016 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7017 22, 23, 24, 25, 26, 27, 28, 29, 30,
7018 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7019 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7020
7021 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7022 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7023 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7024 22, 23, 24, 25, 26, 27, 28,
7025 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7026 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7027 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7028 22, 23, 24, 25, 26, 27, 28, 29, 30,
7029 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7030 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7031 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7032 22, 23, 24, 25, 26, 27, 28, 29, 30,
7033 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7034 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7035 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7036 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7037 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7038 22, 23, 24, 25, 26, 27, 28, 29, 30,
7039 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7040 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7041 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7042 22, 23, 24, 25, 26, 27, 28, 29, 30,
7043 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7044 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7045
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, 31,
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,
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 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7061 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7062 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7063 22, 23, 24, 25, 26, 27, 28, 29, 30,
7064 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7065 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7066 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7067 22, 23, 24, 25, 26, 27, 28, 29, 30,
7068 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7069 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7070
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, 31,
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,
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 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7086 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7087 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7088 22, 23, 24, 25, 26, 27, 28, 29, 30,
7089 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7090 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7091 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7092 22, 23, 24, 25, 26, 27, 28, 29, 30,
7093 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7094 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7095
7096static const char kMonthInYear[] = {
7097 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,
7098 0, 0, 0, 0, 0, 0,
7099 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,
7100 1, 1, 1,
7101 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,
7102 2, 2, 2, 2, 2, 2,
7103 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,
7104 3, 3, 3, 3, 3,
7105 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,
7106 4, 4, 4, 4, 4, 4,
7107 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,
7108 5, 5, 5, 5, 5,
7109 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,
7110 6, 6, 6, 6, 6, 6,
7111 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,
7112 7, 7, 7, 7, 7, 7,
7113 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,
7114 8, 8, 8, 8, 8,
7115 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,
7116 9, 9, 9, 9, 9, 9,
7117 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7118 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7119 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7120 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7121
7122 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,
7123 0, 0, 0, 0, 0, 0,
7124 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,
7125 1, 1, 1,
7126 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,
7127 2, 2, 2, 2, 2, 2,
7128 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,
7129 3, 3, 3, 3, 3,
7130 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,
7131 4, 4, 4, 4, 4, 4,
7132 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,
7133 5, 5, 5, 5, 5,
7134 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,
7135 6, 6, 6, 6, 6, 6,
7136 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,
7137 7, 7, 7, 7, 7, 7,
7138 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,
7139 8, 8, 8, 8, 8,
7140 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,
7141 9, 9, 9, 9, 9, 9,
7142 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7143 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7144 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7145 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7146
7147 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,
7148 0, 0, 0, 0, 0, 0,
7149 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,
7150 1, 1, 1, 1,
7151 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,
7152 2, 2, 2, 2, 2, 2,
7153 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,
7154 3, 3, 3, 3, 3,
7155 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,
7156 4, 4, 4, 4, 4, 4,
7157 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,
7158 5, 5, 5, 5, 5,
7159 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,
7160 6, 6, 6, 6, 6, 6,
7161 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,
7162 7, 7, 7, 7, 7, 7,
7163 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,
7164 8, 8, 8, 8, 8,
7165 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,
7166 9, 9, 9, 9, 9, 9,
7167 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7168 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7169 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7170 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7171
7172 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,
7173 0, 0, 0, 0, 0, 0,
7174 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,
7175 1, 1, 1,
7176 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,
7177 2, 2, 2, 2, 2, 2,
7178 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,
7179 3, 3, 3, 3, 3,
7180 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,
7181 4, 4, 4, 4, 4, 4,
7182 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,
7183 5, 5, 5, 5, 5,
7184 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,
7185 6, 6, 6, 6, 6, 6,
7186 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,
7187 7, 7, 7, 7, 7, 7,
7188 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,
7189 8, 8, 8, 8, 8,
7190 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,
7191 9, 9, 9, 9, 9, 9,
7192 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7193 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7194 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7195 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7196
7197
7198// This function works for dates from 1970 to 2099.
7199static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007200 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007201#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007202 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007203#endif
7204
7205 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7206 date %= kDaysIn4Years;
7207
7208 month = kMonthInYear[date];
7209 day = kDayInYear[date];
7210
7211 ASSERT(MakeDay(year, month, day) == save_date);
7212}
7213
7214
7215static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007216 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007217#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007218 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007219#endif
7220
7221 date += kDaysOffset;
7222 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7223 date %= kDaysIn400Years;
7224
7225 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7226
7227 date--;
7228 int yd1 = date / kDaysIn100Years;
7229 date %= kDaysIn100Years;
7230 year += 100 * yd1;
7231
7232 date++;
7233 int yd2 = date / kDaysIn4Years;
7234 date %= kDaysIn4Years;
7235 year += 4 * yd2;
7236
7237 date--;
7238 int yd3 = date / 365;
7239 date %= 365;
7240 year += yd3;
7241
7242 bool is_leap = (!yd1 || yd2) && !yd3;
7243
7244 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007245 ASSERT(is_leap || (date >= 0));
7246 ASSERT((date < 365) || (is_leap && (date < 366)));
7247 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7248 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7249 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007250
7251 if (is_leap) {
7252 day = kDayInYear[2*365 + 1 + date];
7253 month = kMonthInYear[2*365 + 1 + date];
7254 } else {
7255 day = kDayInYear[date];
7256 month = kMonthInYear[date];
7257 }
7258
7259 ASSERT(MakeDay(year, month, day) == save_date);
7260}
7261
7262
7263static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007264 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007265 if (date >= 0 && date < 32 * kDaysIn4Years) {
7266 DateYMDFromTimeAfter1970(date, year, month, day);
7267 } else {
7268 DateYMDFromTimeSlow(date, year, month, day);
7269 }
7270}
7271
7272
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007273RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007274 NoHandleAllocation ha;
7275 ASSERT(args.length() == 2);
7276
7277 CONVERT_DOUBLE_CHECKED(t, args[0]);
7278 CONVERT_CHECKED(JSArray, res_array, args[1]);
7279
7280 int year, month, day;
7281 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7282
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007283 RUNTIME_ASSERT(res_array->elements()->map() ==
7284 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007285 FixedArray* elms = FixedArray::cast(res_array->elements());
7286 RUNTIME_ASSERT(elms->length() == 3);
7287
7288 elms->set(0, Smi::FromInt(year));
7289 elms->set(1, Smi::FromInt(month));
7290 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007291
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007292 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007293}
7294
7295
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007296RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007297 NoHandleAllocation ha;
7298 ASSERT(args.length() == 3);
7299
7300 JSFunction* callee = JSFunction::cast(args[0]);
7301 Object** parameters = reinterpret_cast<Object**>(args[1]);
7302 const int length = Smi::cast(args[2])->value();
7303
lrn@chromium.org303ada72010-10-27 09:33:13 +00007304 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007305 { MaybeObject* maybe_result =
7306 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007307 if (!maybe_result->ToObject(&result)) return maybe_result;
7308 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007309 // Allocate the elements if needed.
7310 if (length > 0) {
7311 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007312 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007313 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007314 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7315 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007316
7317 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007318 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007319 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007320 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007321
7322 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007323 for (int i = 0; i < length; i++) {
7324 array->set(i, *--parameters, mode);
7325 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007326 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007327 }
7328 return result;
7329}
7330
7331
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007332RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007333 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007334 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007335 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007336 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007337 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007338
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007339 // Allocate global closures in old space and allocate local closures
7340 // in new space. Additionally pretenure closures that are assigned
7341 // directly to properties.
7342 pretenure = pretenure || (context->global_context() == *context);
7343 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007344 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007345 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7346 context,
7347 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007348 return *result;
7349}
7350
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007351
7352static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7353 int* total_argc) {
7354 // Find frame containing arguments passed to the caller.
7355 JavaScriptFrameIterator it;
7356 JavaScriptFrame* frame = it.frame();
7357 List<JSFunction*> functions(2);
7358 frame->GetFunctions(&functions);
7359 if (functions.length() > 1) {
7360 int inlined_frame_index = functions.length() - 1;
7361 JSFunction* inlined_function = functions[inlined_frame_index];
7362 int args_count = inlined_function->shared()->formal_parameter_count();
7363 ScopedVector<SlotRef> args_slots(args_count);
7364 SlotRef::ComputeSlotMappingForArguments(frame,
7365 inlined_frame_index,
7366 &args_slots);
7367
7368 *total_argc = bound_argc + args_count;
7369 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7370 for (int i = 0; i < args_count; i++) {
7371 Handle<Object> val = args_slots[i].GetValue();
7372 param_data[bound_argc + i] = val.location();
7373 }
7374 return param_data;
7375 } else {
7376 it.AdvanceToArgumentsFrame();
7377 frame = it.frame();
7378 int args_count = frame->ComputeParametersCount();
7379
7380 *total_argc = bound_argc + args_count;
7381 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7382 for (int i = 0; i < args_count; i++) {
7383 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7384 param_data[bound_argc + i] = val.location();
7385 }
7386 return param_data;
7387 }
7388}
7389
7390
7391RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007392 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007393 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007394 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007395 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007396
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007397 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007398 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007399 int bound_argc = 0;
7400 if (!args[1]->IsNull()) {
7401 CONVERT_ARG_CHECKED(JSArray, params, 1);
7402 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007403 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007404 bound_argc = Smi::cast(params->length())->value();
7405 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007406
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007407 int total_argc = 0;
7408 SmartPointer<Object**> param_data =
7409 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007410 for (int i = 0; i < bound_argc; i++) {
7411 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007412 param_data[i] = val.location();
7413 }
7414
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007415 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007416 Handle<Object> result =
7417 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007418 if (exception) {
7419 return Failure::Exception();
7420 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007421
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007422 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007423 return *result;
7424}
7425
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007426
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007427static void TrySettingInlineConstructStub(Isolate* isolate,
7428 Handle<JSFunction> function) {
7429 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007430 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007431 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007432 }
7433 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007434 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007435 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007436 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007437 function->shared()->set_construct_stub(
7438 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007439 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007440 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007441}
7442
7443
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007444RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007445 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007446 ASSERT(args.length() == 1);
7447
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007448 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007449
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007450 // If the constructor isn't a proper function we throw a type error.
7451 if (!constructor->IsJSFunction()) {
7452 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7453 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007454 isolate->factory()->NewTypeError("not_constructor", arguments);
7455 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007456 }
7457
7458 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007459
7460 // If function should not have prototype, construction is not allowed. In this
7461 // case generated code bailouts here, since function has no initial_map.
7462 if (!function->should_have_prototype()) {
7463 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7464 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007465 isolate->factory()->NewTypeError("not_constructor", arguments);
7466 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007467 }
7468
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007469#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007470 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007471 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007472 if (debug->StepInActive()) {
7473 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007474 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007475#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007476
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007477 if (function->has_initial_map()) {
7478 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007479 // The 'Function' function ignores the receiver object when
7480 // called using 'new' and creates a new JSFunction object that
7481 // is returned. The receiver object is only used for error
7482 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007483 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007484 // allocate JSFunctions since it does not properly initialize
7485 // the shared part of the function. Since the receiver is
7486 // ignored anyway, we use the global object as the receiver
7487 // instead of a new JSFunction object. This way, errors are
7488 // reported the same way whether or not 'Function' is called
7489 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007490 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007491 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007492 }
7493
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007494 // The function should be compiled for the optimization hints to be
7495 // available. We cannot use EnsureCompiled because that forces a
7496 // compilation through the shared function info which makes it
7497 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007498 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007499 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007500
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007501 if (!function->has_initial_map() &&
7502 shared->IsInobjectSlackTrackingInProgress()) {
7503 // The tracking is already in progress for another function. We can only
7504 // track one initial_map at a time, so we force the completion before the
7505 // function is called as a constructor for the first time.
7506 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007507 }
7508
7509 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007510 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7511 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007512 // Delay setting the stub if inobject slack tracking is in progress.
7513 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007514 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007515 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007516
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007517 isolate->counters()->constructed_objects()->Increment();
7518 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007519
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007520 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007521}
7522
7523
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007524RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007525 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007526 ASSERT(args.length() == 1);
7527
7528 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7529 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007530 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007531
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007532 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007533}
7534
7535
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007536RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007537 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007538 ASSERT(args.length() == 1);
7539
7540 Handle<JSFunction> function = args.at<JSFunction>(0);
7541#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007542 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007543 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007544 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007545 PrintF("]\n");
7546 }
7547#endif
7548
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007549 // Compile the target function. Here we compile using CompileLazyInLoop in
7550 // order to get the optimized version. This helps code like delta-blue
7551 // that calls performance-critical routines through constructors. A
7552 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7553 // direct call. Since the in-loop tracking takes place through CallICs
7554 // this means that things called through constructors are never known to
7555 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007556 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007557 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007558 return Failure::Exception();
7559 }
7560
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007561 // All done. Return the compiled code.
7562 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007563 return function->code();
7564}
7565
7566
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007567RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007568 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007569 ASSERT(args.length() == 1);
7570 Handle<JSFunction> function = args.at<JSFunction>(0);
7571 // If the function is not optimizable or debugger is active continue using the
7572 // code from the full compiler.
7573 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007574 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007575 if (FLAG_trace_opt) {
7576 PrintF("[failed to optimize ");
7577 function->PrintName();
7578 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7579 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007580 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007581 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007582 function->ReplaceCode(function->shared()->code());
7583 return function->code();
7584 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007585 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007586 return function->code();
7587 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007588 if (FLAG_trace_opt) {
7589 PrintF("[failed to optimize ");
7590 function->PrintName();
7591 PrintF(": optimized compilation failed]\n");
7592 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007593 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007594 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007595}
7596
7597
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007598RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007599 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007600 ASSERT(args.length() == 1);
7601 RUNTIME_ASSERT(args[0]->IsSmi());
7602 Deoptimizer::BailoutType type =
7603 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007604 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7605 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007606 int frames = deoptimizer->output_count();
7607
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007608 deoptimizer->MaterializeHeapNumbers();
7609 delete deoptimizer;
7610
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007611 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007612 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007613 for (int i = 0; i < frames - 1; i++) it.Advance();
7614 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007615
7616 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007617 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007618 Handle<Object> arguments;
7619 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007620 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007621 if (arguments.is_null()) {
7622 // FunctionGetArguments can't throw an exception, so cast away the
7623 // doubt with an assert.
7624 arguments = Handle<Object>(
7625 Accessors::FunctionGetArguments(*function,
7626 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007627 ASSERT(*arguments != isolate->heap()->null_value());
7628 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007629 }
7630 frame->SetExpression(i, *arguments);
7631 }
7632 }
7633
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007634 isolate->compilation_cache()->MarkForLazyOptimizing(function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007635 if (type == Deoptimizer::EAGER) {
7636 RUNTIME_ASSERT(function->IsOptimized());
7637 } else {
7638 RUNTIME_ASSERT(!function->IsOptimized());
7639 }
7640
7641 // Avoid doing too much work when running with --always-opt and keep
7642 // the optimized code around.
7643 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007644 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007645 }
7646
7647 // Count the number of optimized activations of the function.
7648 int activations = 0;
7649 while (!it.done()) {
7650 JavaScriptFrame* frame = it.frame();
7651 if (frame->is_optimized() && frame->function() == *function) {
7652 activations++;
7653 }
7654 it.Advance();
7655 }
7656
7657 // TODO(kasperl): For now, we cannot support removing the optimized
7658 // code when we have recursive invocations of the same function.
7659 if (activations == 0) {
7660 if (FLAG_trace_deopt) {
7661 PrintF("[removing optimized code for: ");
7662 function->PrintName();
7663 PrintF("]\n");
7664 }
7665 function->ReplaceCode(function->shared()->code());
7666 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007667 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007668}
7669
7670
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007671RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007672 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007673 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007674 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007675}
7676
7677
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007678RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007679 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007680 ASSERT(args.length() == 1);
7681 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007682 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007683
7684 Deoptimizer::DeoptimizeFunction(*function);
7685
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007686 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007687}
7688
7689
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007690RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7691 HandleScope scope(isolate);
7692 ASSERT(args.length() == 1);
7693 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7694 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7695 function->MarkForLazyRecompilation();
7696 return isolate->heap()->undefined_value();
7697}
7698
7699
lrn@chromium.org1c092762011-05-09 09:42:16 +00007700RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
7701 HandleScope scope(isolate);
7702 ASSERT(args.length() == 1);
7703 if (!V8::UseCrankshaft()) {
7704 return Smi::FromInt(4); // 4 == "never".
7705 }
7706 if (FLAG_always_opt) {
7707 return Smi::FromInt(3); // 3 == "always".
7708 }
7709 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7710 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
7711 : Smi::FromInt(2); // 2 == "no".
7712}
7713
7714
7715RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
7716 HandleScope scope(isolate);
7717 ASSERT(args.length() == 1);
7718 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7719 return Smi::FromInt(function->shared()->opt_count());
7720}
7721
7722
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007723RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007724 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007725 ASSERT(args.length() == 1);
7726 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7727
7728 // We're not prepared to handle a function with arguments object.
7729 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7730
7731 // We have hit a back edge in an unoptimized frame for a function that was
7732 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007733 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007734 // Keep track of whether we've succeeded in optimizing.
7735 bool succeeded = unoptimized->optimizable();
7736 if (succeeded) {
7737 // If we are trying to do OSR when there are already optimized
7738 // activations of the function, it means (a) the function is directly or
7739 // indirectly recursive and (b) an optimized invocation has been
7740 // deoptimized so that we are currently in an unoptimized activation.
7741 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007742 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007743 while (succeeded && !it.done()) {
7744 JavaScriptFrame* frame = it.frame();
7745 succeeded = !frame->is_optimized() || frame->function() != *function;
7746 it.Advance();
7747 }
7748 }
7749
7750 int ast_id = AstNode::kNoNumber;
7751 if (succeeded) {
7752 // The top JS function is this one, the PC is somewhere in the
7753 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007754 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007755 JavaScriptFrame* frame = it.frame();
7756 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007757 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007758 ASSERT(unoptimized->contains(frame->pc()));
7759
7760 // Use linear search of the unoptimized code's stack check table to find
7761 // the AST id matching the PC.
7762 Address start = unoptimized->instruction_start();
7763 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007764 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007765 uint32_t table_length = Memory::uint32_at(table_cursor);
7766 table_cursor += kIntSize;
7767 for (unsigned i = 0; i < table_length; ++i) {
7768 // Table entries are (AST id, pc offset) pairs.
7769 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7770 if (pc_offset == target_pc_offset) {
7771 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7772 break;
7773 }
7774 table_cursor += 2 * kIntSize;
7775 }
7776 ASSERT(ast_id != AstNode::kNoNumber);
7777 if (FLAG_trace_osr) {
7778 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7779 function->PrintName();
7780 PrintF("]\n");
7781 }
7782
7783 // Try to compile the optimized code. A true return value from
7784 // CompileOptimized means that compilation succeeded, not necessarily
7785 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007786 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7787 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007788 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7789 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007790 if (data->OsrPcOffset()->value() >= 0) {
7791 if (FLAG_trace_osr) {
7792 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007793 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007794 }
7795 ASSERT(data->OsrAstId()->value() == ast_id);
7796 } else {
7797 // We may never generate the desired OSR entry if we emit an
7798 // early deoptimize.
7799 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007800 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007801 } else {
7802 succeeded = false;
7803 }
7804 }
7805
7806 // Revert to the original stack checks in the original unoptimized code.
7807 if (FLAG_trace_osr) {
7808 PrintF("[restoring original stack checks in ");
7809 function->PrintName();
7810 PrintF("]\n");
7811 }
7812 StackCheckStub check_stub;
7813 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007814 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007815 Deoptimizer::RevertStackCheckCode(*unoptimized,
7816 *check_code,
7817 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007818
7819 // Allow OSR only at nesting level zero again.
7820 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7821
7822 // If the optimization attempt succeeded, return the AST id tagged as a
7823 // smi. This tells the builtin that we need to translate the unoptimized
7824 // frame to an optimized one.
7825 if (succeeded) {
7826 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7827 return Smi::FromInt(ast_id);
7828 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007829 if (function->IsMarkedForLazyRecompilation()) {
7830 function->ReplaceCode(function->shared()->code());
7831 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007832 return Smi::FromInt(-1);
7833 }
7834}
7835
7836
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007837RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007838 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007839 ASSERT(args.length() == 1);
7840 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7841 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7842}
7843
7844
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007845RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007846 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007847 ASSERT(args.length() == 1);
7848 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7849 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7850}
7851
7852
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007853RUNTIME_FUNCTION(MaybeObject*, Runtime_NewContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007854 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007855 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007856
kasper.lund7276f142008-07-30 08:49:36 +00007857 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007858 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007859 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007860 { MaybeObject* maybe_result =
7861 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007862 if (!maybe_result->ToObject(&result)) return maybe_result;
7863 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007864
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007865 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007866
kasper.lund7276f142008-07-30 08:49:36 +00007867 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007868}
7869
lrn@chromium.org303ada72010-10-27 09:33:13 +00007870
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007871MUST_USE_RESULT static MaybeObject* PushContextHelper(Isolate* isolate,
7872 Object* object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007873 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007874 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007875 Object* js_object = object;
7876 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007877 MaybeObject* maybe_js_object = js_object->ToObject();
7878 if (!maybe_js_object->ToObject(&js_object)) {
7879 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7880 return maybe_js_object;
7881 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007882 HandleScope scope(isolate);
7883 Handle<Object> handle(object, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007884 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007885 isolate->factory()->NewTypeError("with_expression",
7886 HandleVector(&handle, 1));
7887 return isolate->Throw(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007888 }
7889 }
7890
lrn@chromium.org303ada72010-10-27 09:33:13 +00007891 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007892 { MaybeObject* maybe_result = isolate->heap()->AllocateWithContext(
7893 isolate->context(), JSObject::cast(js_object), is_catch_context);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007894 if (!maybe_result->ToObject(&result)) return maybe_result;
7895 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007896
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007897 Context* context = Context::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007898 isolate->set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007899
kasper.lund7276f142008-07-30 08:49:36 +00007900 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007901}
7902
7903
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007904RUNTIME_FUNCTION(MaybeObject*, Runtime_PushContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007905 NoHandleAllocation ha;
7906 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007907 return PushContextHelper(isolate, args[0], false);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007908}
7909
7910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007911RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007912 NoHandleAllocation ha;
7913 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007914 return PushContextHelper(isolate, args[0], true);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007915}
7916
7917
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007918RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007919 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007920 ASSERT(args.length() == 2);
7921
7922 CONVERT_ARG_CHECKED(Context, context, 0);
7923 CONVERT_ARG_CHECKED(String, name, 1);
7924
7925 int index;
7926 PropertyAttributes attributes;
7927 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007928 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007929
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007930 // If the slot was not found the result is true.
7931 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007932 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007933 }
7934
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007935 // If the slot was found in a context, it should be DONT_DELETE.
7936 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007937 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007938 }
7939
7940 // The slot was found in a JSObject, either a context extension object,
7941 // the global object, or an arguments object. Try to delete it
7942 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7943 // which allows deleting all parameters in functions that mention
7944 // 'arguments', we do this even for the case of slots found on an
7945 // arguments object. The slot was found on an arguments object if the
7946 // index is non-negative.
7947 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7948 if (index >= 0) {
7949 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7950 } else {
7951 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7952 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007953}
7954
7955
ager@chromium.orga1645e22009-09-09 19:27:10 +00007956// A mechanism to return a pair of Object pointers in registers (if possible).
7957// How this is achieved is calling convention-dependent.
7958// All currently supported x86 compiles uses calling conventions that are cdecl
7959// variants where a 64-bit value is returned in two 32-bit registers
7960// (edx:eax on ia32, r1:r0 on ARM).
7961// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7962// In Win64 calling convention, a struct of two pointers is returned in memory,
7963// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007964#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007965struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007966 MaybeObject* x;
7967 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007968};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007969
lrn@chromium.org303ada72010-10-27 09:33:13 +00007970static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007971 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007972 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7973 // In Win64 they are assigned to a hidden first argument.
7974 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007975}
7976#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007977typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007978static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007979 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007980 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007981}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007982#endif
7983
7984
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007985static inline MaybeObject* Unhole(Heap* heap,
7986 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007987 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007988 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7989 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007990 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007991}
7992
7993
danno@chromium.org40cb8782011-05-25 07:58:50 +00007994static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
7995 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007996 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007997 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007998 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007999 JSFunction* context_extension_function =
8000 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008001 // If the holder isn't a context extension object, we just return it
8002 // as the receiver. This allows arguments objects to be used as
8003 // receivers, but only if they are put in the context scope chain
8004 // explicitly via a with-statement.
8005 Object* constructor = holder->map()->constructor();
8006 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008007 // Fall back to using the global object as the implicit receiver if
8008 // the property turns out to be a local variable allocated in a
8009 // context extension object - introduced via eval. Implicit global
8010 // receivers are indicated with the hole value.
8011 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008012}
8013
8014
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008015static ObjectPair LoadContextSlotHelper(Arguments args,
8016 Isolate* isolate,
8017 bool throw_error) {
8018 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008019 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008020
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008021 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008022 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008023 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008024 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008025 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008026
8027 int index;
8028 PropertyAttributes attributes;
8029 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008030 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008031
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008032 // If the index is non-negative, the slot has been found in a local
8033 // variable or a parameter. Read it from the context object or the
8034 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008035 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008036 // If the "property" we were looking for is a local variable or an
8037 // argument in a context, the receiver is the global object; see
8038 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008039 //
8040 // Use the hole as the receiver to signal that the receiver is
8041 // implicit and that the global receiver should be used.
8042 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008043 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008044 ? Context::cast(*holder)->get(index)
8045 : JSObject::cast(*holder)->GetElement(index);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008046 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008047 }
8048
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008049 // If the holder is found, we read the property from it.
8050 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008051 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008052 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008053 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008054 if (object->IsGlobalObject()) {
8055 receiver = GlobalObject::cast(object)->global_receiver();
8056 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008057 // Use the hole as the receiver to signal that the receiver is
8058 // implicit and that the global receiver should be used.
8059 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008060 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008061 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008062 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008063
8064 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008065 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008066
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008067 // No need to unhole the value here. This is taken care of by the
8068 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008069 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008070 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008071 }
8072
8073 if (throw_error) {
8074 // The property doesn't exist - throw exception.
8075 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008076 isolate->factory()->NewReferenceError("not_defined",
8077 HandleVector(&name, 1));
8078 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008079 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008080 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008081 return MakePair(isolate->heap()->undefined_value(),
8082 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008083 }
8084}
8085
8086
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008087RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008088 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008089}
8090
8091
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008092RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008093 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008094}
8095
8096
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008097RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008098 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008099 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008100
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008101 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008102 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008103 CONVERT_ARG_CHECKED(String, name, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008104 CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
8105 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8106 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008107 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008108
8109 int index;
8110 PropertyAttributes attributes;
8111 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008112 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008113
8114 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008115 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008116 // Ignore if read_only variable.
8117 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008118 // Context is a fixed array and set cannot fail.
8119 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008120 } else if (strict_mode == kStrictMode) {
8121 // Setting read only property in strict mode.
8122 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008123 isolate->factory()->NewTypeError("strict_cannot_assign",
8124 HandleVector(&name, 1));
8125 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008126 }
8127 } else {
8128 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008129 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008130 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008131 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008132 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008133 return Failure::Exception();
8134 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008135 }
8136 return *value;
8137 }
8138
8139 // Slow case: The property is not in a FixedArray context.
8140 // It is either in an JSObject extension context or it was not found.
8141 Handle<JSObject> context_ext;
8142
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008143 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008144 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008145 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008146 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008147 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008148 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008149
8150 if (strict_mode == kStrictMode) {
8151 // Throw in strict mode (assignment to undefined variable).
8152 Handle<Object> error =
8153 isolate->factory()->NewReferenceError(
8154 "not_defined", HandleVector(&name, 1));
8155 return isolate->Throw(*error);
8156 }
8157 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008158 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008159 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008160 }
8161
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008162 // Set the property, but ignore if read_only variable on the context
8163 // extension object itself.
8164 if ((attributes & READ_ONLY) == 0 ||
8165 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008166 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008167 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008168 SetProperty(context_ext, name, value, NONE, strict_mode));
8169 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008170 // Setting read only property in strict mode.
8171 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008172 isolate->factory()->NewTypeError(
8173 "strict_cannot_assign", HandleVector(&name, 1));
8174 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008175 }
8176 return *value;
8177}
8178
8179
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008180RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008181 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008182 ASSERT(args.length() == 1);
8183
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008184 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008185}
8186
8187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008188RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008189 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008190 ASSERT(args.length() == 1);
8191
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008192 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008193}
8194
8195
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008196RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008197 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008198 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008199}
8200
8201
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008202RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008203 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008204 ASSERT(args.length() == 1);
8205
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008206 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008207 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008208 isolate->factory()->NewReferenceError("not_defined",
8209 HandleVector(&name, 1));
8210 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008211}
8212
8213
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008214RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008215 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008216
8217 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008218 if (isolate->stack_guard()->IsStackOverflow()) {
8219 NoHandleAllocation na;
8220 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008221 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008222
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008223 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008224}
8225
8226
8227// NOTE: These PrintXXX functions are defined for all builds (not just
8228// DEBUG builds) because we may want to be able to trace function
8229// calls in all modes.
8230static void PrintString(String* str) {
8231 // not uncommon to have empty strings
8232 if (str->length() > 0) {
8233 SmartPointer<char> s =
8234 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8235 PrintF("%s", *s);
8236 }
8237}
8238
8239
8240static void PrintObject(Object* obj) {
8241 if (obj->IsSmi()) {
8242 PrintF("%d", Smi::cast(obj)->value());
8243 } else if (obj->IsString() || obj->IsSymbol()) {
8244 PrintString(String::cast(obj));
8245 } else if (obj->IsNumber()) {
8246 PrintF("%g", obj->Number());
8247 } else if (obj->IsFailure()) {
8248 PrintF("<failure>");
8249 } else if (obj->IsUndefined()) {
8250 PrintF("<undefined>");
8251 } else if (obj->IsNull()) {
8252 PrintF("<null>");
8253 } else if (obj->IsTrue()) {
8254 PrintF("<true>");
8255 } else if (obj->IsFalse()) {
8256 PrintF("<false>");
8257 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008258 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008259 }
8260}
8261
8262
8263static int StackSize() {
8264 int n = 0;
8265 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8266 return n;
8267}
8268
8269
8270static void PrintTransition(Object* result) {
8271 // indentation
8272 { const int nmax = 80;
8273 int n = StackSize();
8274 if (n <= nmax)
8275 PrintF("%4d:%*s", n, n, "");
8276 else
8277 PrintF("%4d:%*s", n, nmax, "...");
8278 }
8279
8280 if (result == NULL) {
8281 // constructor calls
8282 JavaScriptFrameIterator it;
8283 JavaScriptFrame* frame = it.frame();
8284 if (frame->IsConstructor()) PrintF("new ");
8285 // function name
8286 Object* fun = frame->function();
8287 if (fun->IsJSFunction()) {
8288 PrintObject(JSFunction::cast(fun)->shared()->name());
8289 } else {
8290 PrintObject(fun);
8291 }
8292 // function arguments
8293 // (we are intentionally only printing the actually
8294 // supplied parameters, not all parameters required)
8295 PrintF("(this=");
8296 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008297 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008298 for (int i = 0; i < length; i++) {
8299 PrintF(", ");
8300 PrintObject(frame->GetParameter(i));
8301 }
8302 PrintF(") {\n");
8303
8304 } else {
8305 // function result
8306 PrintF("} -> ");
8307 PrintObject(result);
8308 PrintF("\n");
8309 }
8310}
8311
8312
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008313RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008314 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008315 NoHandleAllocation ha;
8316 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008317 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008318}
8319
8320
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008321RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008322 NoHandleAllocation ha;
8323 PrintTransition(args[0]);
8324 return args[0]; // return TOS
8325}
8326
8327
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008328RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008329 NoHandleAllocation ha;
8330 ASSERT(args.length() == 1);
8331
8332#ifdef DEBUG
8333 if (args[0]->IsString()) {
8334 // If we have a string, assume it's a code "marker"
8335 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008336 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008337 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008338 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8339 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008340 } else {
8341 PrintF("DebugPrint: ");
8342 }
8343 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008344 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008345 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008346 HeapObject::cast(args[0])->map()->Print();
8347 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008348#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008349 // ShortPrint is available in release mode. Print is not.
8350 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008351#endif
8352 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008353 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008354
8355 return args[0]; // return TOS
8356}
8357
8358
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008359RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008360 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008361 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008362 isolate->PrintStack();
8363 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008364}
8365
8366
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008367RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008368 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008369 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008370
8371 // According to ECMA-262, section 15.9.1, page 117, the precision of
8372 // the number in a Date object representing a particular instant in
8373 // time is milliseconds. Therefore, we floor the result of getting
8374 // the OS time.
8375 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008376 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008377}
8378
8379
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008380RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008381 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008382 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008383
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008384 CONVERT_ARG_CHECKED(String, str, 0);
8385 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008386
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008387 CONVERT_ARG_CHECKED(JSArray, output, 1);
8388 RUNTIME_ASSERT(output->HasFastElements());
8389
8390 AssertNoAllocation no_allocation;
8391
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008392 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008393 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8394 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008395 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008396 result = DateParser::Parse(str->ToAsciiVector(),
8397 output_array,
8398 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008399 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008400 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008401 result = DateParser::Parse(str->ToUC16Vector(),
8402 output_array,
8403 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008404 }
8405
8406 if (result) {
8407 return *output;
8408 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008409 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008410 }
8411}
8412
8413
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008414RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008415 NoHandleAllocation ha;
8416 ASSERT(args.length() == 1);
8417
8418 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008419 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008420 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008421}
8422
8423
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008424RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008425 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008426 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008427
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008428 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008429}
8430
8431
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008432RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008433 NoHandleAllocation ha;
8434 ASSERT(args.length() == 1);
8435
8436 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008437 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008438}
8439
8440
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008441RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008442 ASSERT(args.length() == 1);
8443 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008444 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008445 return JSGlobalObject::cast(global)->global_receiver();
8446}
8447
8448
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008449RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008450 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008451 ASSERT_EQ(1, args.length());
8452 CONVERT_ARG_CHECKED(String, source, 0);
8453
8454 Handle<Object> result = JsonParser::Parse(source);
8455 if (result.is_null()) {
8456 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008457 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008458 return Failure::Exception();
8459 }
8460 return *result;
8461}
8462
8463
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008464bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8465 Handle<Context> context) {
8466 if (context->allow_code_gen_from_strings()->IsFalse()) {
8467 // Check with callback if set.
8468 AllowCodeGenerationFromStringsCallback callback =
8469 isolate->allow_code_gen_callback();
8470 if (callback == NULL) {
8471 // No callback set and code generation disallowed.
8472 return false;
8473 } else {
8474 // Callback set. Let it decide if code generation is allowed.
8475 VMState state(isolate, EXTERNAL);
8476 return callback(v8::Utils::ToLocal(context));
8477 }
8478 }
8479 return true;
8480}
8481
8482
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008483RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008484 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008485 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008486 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008487
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008488 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008489 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008490
8491 // Check if global context allows code generation from
8492 // strings. Throw an exception if it doesn't.
8493 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8494 return isolate->Throw(*isolate->factory()->NewError(
8495 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8496 }
8497
8498 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008499 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8500 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008501 true,
8502 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008503 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008504 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008505 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8506 context,
8507 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008508 return *fun;
8509}
8510
8511
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008512static ObjectPair CompileGlobalEval(Isolate* isolate,
8513 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008514 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008515 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008516 Handle<Context> context = Handle<Context>(isolate->context());
8517 Handle<Context> global_context = Handle<Context>(context->global_context());
8518
8519 // Check if global context allows code generation from
8520 // strings. Throw an exception if it doesn't.
8521 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8522 isolate->Throw(*isolate->factory()->NewError(
8523 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8524 return MakePair(Failure::Exception(), NULL);
8525 }
8526
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008527 // Deal with a normal eval call with a string argument. Compile it
8528 // and return the compiled function bound in the local context.
8529 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8530 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008531 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008532 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008533 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008534 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008535 Handle<JSFunction> compiled =
8536 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008537 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008538 return MakePair(*compiled, *receiver);
8539}
8540
8541
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008542RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008543 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008544
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008545 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008546 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008547 Handle<Object> receiver; // Will be overwritten.
8548
8549 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008550 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008551#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008552 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008553 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008554 StackFrameLocator locator;
8555 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008556 ASSERT(Context::cast(frame->context()) == *context);
8557#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008558
8559 // Find where the 'eval' symbol is bound. It is unaliased only if
8560 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008561 int index = -1;
8562 PropertyAttributes attributes = ABSENT;
8563 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008564 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8565 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008566 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008567 // Stop search when eval is found or when the global context is
8568 // reached.
8569 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008570 if (context->is_function_context()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008571 context = Handle<Context>(Context::cast(context->closure()->context()),
8572 isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008573 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008574 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008575 }
8576 }
8577
iposva@chromium.org245aa852009-02-10 00:49:54 +00008578 // If eval could not be resolved, it has been deleted and we need to
8579 // throw a reference error.
8580 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008581 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008582 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008583 isolate->factory()->NewReferenceError("not_defined",
8584 HandleVector(&name, 1));
8585 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008586 }
8587
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008588 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008589 // 'eval' is not bound in the global context. Just call the function
8590 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00008591 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008592 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008593 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008594 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008595 }
8596
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008597 // 'eval' is bound in the global context, but it may have been overwritten.
8598 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008599 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008600 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008601 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008602 }
8603
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008604 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008605 return CompileGlobalEval(isolate,
8606 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008607 args.at<Object>(2),
8608 static_cast<StrictModeFlag>(
8609 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008610}
8611
8612
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008613RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008614 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008615
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008616 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008617 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008618
8619 // 'eval' is bound in the global context, but it may have been overwritten.
8620 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008621 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008622 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008623 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008624 }
8625
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008626 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008627 return CompileGlobalEval(isolate,
8628 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008629 args.at<Object>(2),
8630 static_cast<StrictModeFlag>(
8631 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008632}
8633
8634
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008635RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008636 // This utility adjusts the property attributes for newly created Function
8637 // object ("new Function(...)") by changing the map.
8638 // All it does is changing the prototype property to enumerable
8639 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008640 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008641 ASSERT(args.length() == 1);
8642 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008643
8644 Handle<Map> map = func->shared()->strict_mode()
8645 ? isolate->strict_mode_function_instance_map()
8646 : isolate->function_instance_map();
8647
8648 ASSERT(func->map()->instance_type() == map->instance_type());
8649 ASSERT(func->map()->instance_size() == map->instance_size());
8650 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008651 return *func;
8652}
8653
8654
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008655RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008656 // Allocate a block of memory in NewSpace (filled with a filler).
8657 // Use as fallback for allocation in generated code when NewSpace
8658 // is full.
8659 ASSERT(args.length() == 1);
8660 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8661 int size = size_smi->value();
8662 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8663 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008664 Heap* heap = isolate->heap();
8665 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008666 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008667 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008668 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008669 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008670 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008671 }
8672 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008673 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008674}
8675
8676
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008677// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008678// array. Returns true if the element was pushed on the stack and
8679// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008680RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008681 ASSERT(args.length() == 2);
8682 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008683 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008684 RUNTIME_ASSERT(array->HasFastElements());
8685 int length = Smi::cast(array->length())->value();
8686 FixedArray* elements = FixedArray::cast(array->elements());
8687 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008688 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008689 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008690 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008691 // Strict not needed. Used for cycle detection in Array join implementation.
8692 { MaybeObject* maybe_obj = array->SetFastElement(length, element,
8693 kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008694 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8695 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008696 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008697}
8698
8699
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008700/**
8701 * A simple visitor visits every element of Array's.
8702 * The backend storage can be a fixed array for fast elements case,
8703 * or a dictionary for sparse array. Since Dictionary is a subtype
8704 * of FixedArray, the class can be used by both fast and slow cases.
8705 * The second parameter of the constructor, fast_elements, specifies
8706 * whether the storage is a FixedArray or Dictionary.
8707 *
8708 * An index limit is used to deal with the situation that a result array
8709 * length overflows 32-bit non-negative integer.
8710 */
8711class ArrayConcatVisitor {
8712 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008713 ArrayConcatVisitor(Isolate* isolate,
8714 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008715 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008716 isolate_(isolate),
8717 storage_(Handle<FixedArray>::cast(
8718 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008719 index_offset_(0u),
8720 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008721
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008722 ~ArrayConcatVisitor() {
8723 clear_storage();
8724 }
8725
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008726 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008727 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008728 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008729
8730 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008731 if (index < static_cast<uint32_t>(storage_->length())) {
8732 storage_->set(index, *elm);
8733 return;
8734 }
8735 // Our initial estimate of length was foiled, possibly by
8736 // getters on the arrays increasing the length of later arrays
8737 // during iteration.
8738 // This shouldn't happen in anything but pathological cases.
8739 SetDictionaryMode(index);
8740 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008741 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008742 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008743 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008744 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008745 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008746 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008747 // Dictionary needed to grow.
8748 clear_storage();
8749 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008750 }
8751}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008752
8753 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008754 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8755 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008756 } else {
8757 index_offset_ += delta;
8758 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008759 }
8760
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008761 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008762 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008763 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008764 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008765 Handle<Map> map;
8766 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008767 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008768 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008769 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008770 }
8771 array->set_map(*map);
8772 array->set_length(*length);
8773 array->set_elements(*storage_);
8774 return array;
8775 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008776
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008777 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008778 // Convert storage to dictionary mode.
8779 void SetDictionaryMode(uint32_t index) {
8780 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008781 Handle<FixedArray> current_storage(*storage_);
8782 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008783 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008784 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8785 for (uint32_t i = 0; i < current_length; i++) {
8786 HandleScope loop_scope;
8787 Handle<Object> element(current_storage->get(i));
8788 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008789 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008790 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008791 if (!new_storage.is_identical_to(slow_storage)) {
8792 slow_storage = loop_scope.CloseAndEscape(new_storage);
8793 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008794 }
8795 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008796 clear_storage();
8797 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008798 fast_elements_ = false;
8799 }
8800
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008801 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008802 isolate_->global_handles()->Destroy(
8803 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008804 }
8805
8806 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008807 storage_ = Handle<FixedArray>::cast(
8808 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008809 }
8810
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008811 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008812 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008813 // Index after last seen index. Always less than or equal to
8814 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008815 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008816 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008817};
8818
8819
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008820static uint32_t EstimateElementCount(Handle<JSArray> array) {
8821 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8822 int element_count = 0;
8823 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008824 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008825 // Fast elements can't have lengths that are not representable by
8826 // a 32-bit signed integer.
8827 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8828 int fast_length = static_cast<int>(length);
8829 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8830 for (int i = 0; i < fast_length; i++) {
8831 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008832 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008833 break;
8834 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008835 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008836 Handle<NumberDictionary> dictionary(
8837 NumberDictionary::cast(array->elements()));
8838 int capacity = dictionary->Capacity();
8839 for (int i = 0; i < capacity; i++) {
8840 Handle<Object> key(dictionary->KeyAt(i));
8841 if (dictionary->IsKey(*key)) {
8842 element_count++;
8843 }
8844 }
8845 break;
8846 }
8847 default:
8848 // External arrays are always dense.
8849 return length;
8850 }
8851 // As an estimate, we assume that the prototype doesn't contain any
8852 // inherited elements.
8853 return element_count;
8854}
8855
8856
8857
8858template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008859static void IterateExternalArrayElements(Isolate* isolate,
8860 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008861 bool elements_are_ints,
8862 bool elements_are_guaranteed_smis,
8863 ArrayConcatVisitor* visitor) {
8864 Handle<ExternalArrayClass> array(
8865 ExternalArrayClass::cast(receiver->elements()));
8866 uint32_t len = static_cast<uint32_t>(array->length());
8867
8868 ASSERT(visitor != NULL);
8869 if (elements_are_ints) {
8870 if (elements_are_guaranteed_smis) {
8871 for (uint32_t j = 0; j < len; j++) {
8872 HandleScope loop_scope;
8873 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8874 visitor->visit(j, e);
8875 }
8876 } else {
8877 for (uint32_t j = 0; j < len; j++) {
8878 HandleScope loop_scope;
8879 int64_t val = static_cast<int64_t>(array->get(j));
8880 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8881 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8882 visitor->visit(j, e);
8883 } else {
8884 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008885 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008886 visitor->visit(j, e);
8887 }
8888 }
8889 }
8890 } else {
8891 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008892 HandleScope loop_scope(isolate);
8893 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008894 visitor->visit(j, e);
8895 }
8896 }
8897}
8898
8899
8900// Used for sorting indices in a List<uint32_t>.
8901static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8902 uint32_t a = *ap;
8903 uint32_t b = *bp;
8904 return (a == b) ? 0 : (a < b) ? -1 : 1;
8905}
8906
8907
8908static void CollectElementIndices(Handle<JSObject> object,
8909 uint32_t range,
8910 List<uint32_t>* indices) {
8911 JSObject::ElementsKind kind = object->GetElementsKind();
8912 switch (kind) {
8913 case JSObject::FAST_ELEMENTS: {
8914 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8915 uint32_t length = static_cast<uint32_t>(elements->length());
8916 if (range < length) length = range;
8917 for (uint32_t i = 0; i < length; i++) {
8918 if (!elements->get(i)->IsTheHole()) {
8919 indices->Add(i);
8920 }
8921 }
8922 break;
8923 }
8924 case JSObject::DICTIONARY_ELEMENTS: {
8925 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008926 uint32_t capacity = dict->Capacity();
8927 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008928 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008929 Handle<Object> k(dict->KeyAt(j));
8930 if (dict->IsKey(*k)) {
8931 ASSERT(k->IsNumber());
8932 uint32_t index = static_cast<uint32_t>(k->Number());
8933 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008934 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008935 }
8936 }
8937 }
8938 break;
8939 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008940 default: {
8941 int dense_elements_length;
8942 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008943 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008944 dense_elements_length =
8945 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008946 break;
8947 }
8948 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008949 dense_elements_length =
8950 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008951 break;
8952 }
8953 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008954 dense_elements_length =
8955 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008956 break;
8957 }
8958 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008959 dense_elements_length =
8960 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008961 break;
8962 }
8963 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008964 dense_elements_length =
8965 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008966 break;
8967 }
8968 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008969 dense_elements_length =
8970 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008971 break;
8972 }
8973 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008974 dense_elements_length =
8975 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008976 break;
8977 }
8978 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008979 dense_elements_length =
8980 ExternalFloatArray::cast(object->elements())->length();
8981 break;
8982 }
8983 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
8984 dense_elements_length =
8985 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008986 break;
8987 }
8988 default:
8989 UNREACHABLE();
8990 dense_elements_length = 0;
8991 break;
8992 }
8993 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8994 if (range <= length) {
8995 length = range;
8996 // We will add all indices, so we might as well clear it first
8997 // and avoid duplicates.
8998 indices->Clear();
8999 }
9000 for (uint32_t i = 0; i < length; i++) {
9001 indices->Add(i);
9002 }
9003 if (length == range) return; // All indices accounted for already.
9004 break;
9005 }
9006 }
9007
9008 Handle<Object> prototype(object->GetPrototype());
9009 if (prototype->IsJSObject()) {
9010 // The prototype will usually have no inherited element indices,
9011 // but we have to check.
9012 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9013 }
9014}
9015
9016
9017/**
9018 * A helper function that visits elements of a JSArray in numerical
9019 * order.
9020 *
9021 * The visitor argument called for each existing element in the array
9022 * with the element index and the element's value.
9023 * Afterwards it increments the base-index of the visitor by the array
9024 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009025 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009026 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009027static bool IterateElements(Isolate* isolate,
9028 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009029 ArrayConcatVisitor* visitor) {
9030 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9031 switch (receiver->GetElementsKind()) {
9032 case JSObject::FAST_ELEMENTS: {
9033 // Run through the elements FixedArray and use HasElement and GetElement
9034 // to check the prototype for missing elements.
9035 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9036 int fast_length = static_cast<int>(length);
9037 ASSERT(fast_length <= elements->length());
9038 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009039 HandleScope loop_scope(isolate);
9040 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009041 if (!element_value->IsTheHole()) {
9042 visitor->visit(j, element_value);
9043 } else if (receiver->HasElement(j)) {
9044 // Call GetElement on receiver, not its prototype, or getters won't
9045 // have the correct receiver.
9046 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009047 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009048 visitor->visit(j, element_value);
9049 }
9050 }
9051 break;
9052 }
9053 case JSObject::DICTIONARY_ELEMENTS: {
9054 Handle<NumberDictionary> dict(receiver->element_dictionary());
9055 List<uint32_t> indices(dict->Capacity() / 2);
9056 // Collect all indices in the object and the prototypes less
9057 // than length. This might introduce duplicates in the indices list.
9058 CollectElementIndices(receiver, length, &indices);
9059 indices.Sort(&compareUInt32);
9060 int j = 0;
9061 int n = indices.length();
9062 while (j < n) {
9063 HandleScope loop_scope;
9064 uint32_t index = indices[j];
9065 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009066 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009067 visitor->visit(index, element);
9068 // Skip to next different index (i.e., omit duplicates).
9069 do {
9070 j++;
9071 } while (j < n && indices[j] == index);
9072 }
9073 break;
9074 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009075 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
9076 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9077 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009078 for (uint32_t j = 0; j < length; j++) {
9079 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
9080 visitor->visit(j, e);
9081 }
9082 break;
9083 }
9084 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
9085 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009086 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009087 break;
9088 }
9089 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9090 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009091 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009092 break;
9093 }
9094 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
9095 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009096 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009097 break;
9098 }
9099 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9100 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009101 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009102 break;
9103 }
9104 case JSObject::EXTERNAL_INT_ELEMENTS: {
9105 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009106 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009107 break;
9108 }
9109 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9110 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009111 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009112 break;
9113 }
9114 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9115 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009116 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009117 break;
9118 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009119 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9120 IterateExternalArrayElements<ExternalDoubleArray, double>(
9121 isolate, receiver, false, false, visitor);
9122 break;
9123 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009124 default:
9125 UNREACHABLE();
9126 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009127 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009128 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009129 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009130}
9131
9132
9133/**
9134 * Array::concat implementation.
9135 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009136 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009137 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009138 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009139RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009140 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009141 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009142
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009143 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9144 int argument_count = static_cast<int>(arguments->length()->Number());
9145 RUNTIME_ASSERT(arguments->HasFastElements());
9146 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009147
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009148 // Pass 1: estimate the length and number of elements of the result.
9149 // The actual length can be larger if any of the arguments have getters
9150 // that mutate other arguments (but will otherwise be precise).
9151 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009152
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009153 uint32_t estimate_result_length = 0;
9154 uint32_t estimate_nof_elements = 0;
9155 {
9156 for (int i = 0; i < argument_count; i++) {
9157 HandleScope loop_scope;
9158 Handle<Object> obj(elements->get(i));
9159 uint32_t length_estimate;
9160 uint32_t element_estimate;
9161 if (obj->IsJSArray()) {
9162 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9163 length_estimate =
9164 static_cast<uint32_t>(array->length()->Number());
9165 element_estimate =
9166 EstimateElementCount(array);
9167 } else {
9168 length_estimate = 1;
9169 element_estimate = 1;
9170 }
9171 // Avoid overflows by capping at kMaxElementCount.
9172 if (JSObject::kMaxElementCount - estimate_result_length <
9173 length_estimate) {
9174 estimate_result_length = JSObject::kMaxElementCount;
9175 } else {
9176 estimate_result_length += length_estimate;
9177 }
9178 if (JSObject::kMaxElementCount - estimate_nof_elements <
9179 element_estimate) {
9180 estimate_nof_elements = JSObject::kMaxElementCount;
9181 } else {
9182 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009183 }
9184 }
9185 }
9186
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009187 // If estimated number of elements is more than half of length, a
9188 // fixed array (fast case) is more time and space-efficient than a
9189 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009190 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009191
9192 Handle<FixedArray> storage;
9193 if (fast_case) {
9194 // The backing storage array must have non-existing elements to
9195 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009196 storage = isolate->factory()->NewFixedArrayWithHoles(
9197 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009198 } else {
9199 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9200 uint32_t at_least_space_for = estimate_nof_elements +
9201 (estimate_nof_elements >> 2);
9202 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009203 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009204 }
9205
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009206 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009207
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009208 for (int i = 0; i < argument_count; i++) {
9209 Handle<Object> obj(elements->get(i));
9210 if (obj->IsJSArray()) {
9211 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009212 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009213 return Failure::Exception();
9214 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009215 } else {
9216 visitor.visit(0, obj);
9217 visitor.increase_index_offset(1);
9218 }
9219 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009220
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009221 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009222}
9223
9224
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009225// This will not allocate (flatten the string), but it may run
9226// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009227RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009228 NoHandleAllocation ha;
9229 ASSERT(args.length() == 1);
9230
9231 CONVERT_CHECKED(String, string, args[0]);
9232 StringInputBuffer buffer(string);
9233 while (buffer.has_more()) {
9234 uint16_t character = buffer.GetNext();
9235 PrintF("%c", character);
9236 }
9237 return string;
9238}
9239
ager@chromium.org5ec48922009-05-05 07:25:34 +00009240// Moves all own elements of an object, that are below a limit, to positions
9241// starting at zero. All undefined values are placed after non-undefined values,
9242// and are followed by non-existing element. Does not change the length
9243// property.
9244// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009245RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009246 ASSERT(args.length() == 2);
9247 CONVERT_CHECKED(JSObject, object, args[0]);
9248 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9249 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009250}
9251
9252
9253// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009254RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009255 ASSERT(args.length() == 2);
9256 CONVERT_CHECKED(JSArray, from, args[0]);
9257 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009258 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009259 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009260 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9261 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009262 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009263 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009264 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009265 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009266 Object* new_map;
9267 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009268 to->set_map(Map::cast(new_map));
9269 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009270 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009271 Object* obj;
9272 { MaybeObject* maybe_obj = from->ResetElements();
9273 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9274 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009275 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009276 return to;
9277}
9278
9279
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009280// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009281RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009282 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009283 CONVERT_CHECKED(JSObject, object, args[0]);
9284 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009285 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009286 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009287 } else if (object->IsJSArray()) {
9288 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009289 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009290 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009291 }
9292}
9293
9294
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009295RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009296 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009297
9298 ASSERT_EQ(3, args.length());
9299
ager@chromium.orgac091b72010-05-05 07:34:42 +00009300 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009301 Handle<Object> key1 = args.at<Object>(1);
9302 Handle<Object> key2 = args.at<Object>(2);
9303
9304 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009305 if (!key1->ToArrayIndex(&index1)
9306 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009307 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009308 }
9309
ager@chromium.orgac091b72010-05-05 07:34:42 +00009310 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9311 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009312 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009313 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009314 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009315
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009316 RETURN_IF_EMPTY_HANDLE(isolate,
9317 SetElement(jsobject, index1, tmp2, kStrictMode));
9318 RETURN_IF_EMPTY_HANDLE(isolate,
9319 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009320
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009321 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009322}
9323
9324
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009325// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009326// might have elements. Can either return keys (positive integers) or
9327// intervals (pair of a negative integer (-start-1) followed by a
9328// positive (length)) or undefined values.
9329// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009330RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009331 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009332 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009333 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009334 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009335 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009336 // Create an array and get all the keys into it, then remove all the
9337 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009338 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009339 int keys_length = keys->length();
9340 for (int i = 0; i < keys_length; i++) {
9341 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009342 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009343 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009344 // Zap invalid keys.
9345 keys->set_undefined(i);
9346 }
9347 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009348 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009349 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009350 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009351 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009352 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009353 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009354 uint32_t actual_length =
9355 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009356 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009357 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009358 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009359 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009360 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009361 }
9362}
9363
9364
9365// DefineAccessor takes an optional final argument which is the
9366// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9367// to the way accessors are implemented, it is set for both the getter
9368// and setter on the first call to DefineAccessor and ignored on
9369// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009370RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009371 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9372 // Compute attributes.
9373 PropertyAttributes attributes = NONE;
9374 if (args.length() == 5) {
9375 CONVERT_CHECKED(Smi, attrs, args[4]);
9376 int value = attrs->value();
9377 // Only attribute bits should be set.
9378 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9379 attributes = static_cast<PropertyAttributes>(value);
9380 }
9381
9382 CONVERT_CHECKED(JSObject, obj, args[0]);
9383 CONVERT_CHECKED(String, name, args[1]);
9384 CONVERT_CHECKED(Smi, flag, args[2]);
9385 CONVERT_CHECKED(JSFunction, fun, args[3]);
9386 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9387}
9388
9389
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009390RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009391 ASSERT(args.length() == 3);
9392 CONVERT_CHECKED(JSObject, obj, args[0]);
9393 CONVERT_CHECKED(String, name, args[1]);
9394 CONVERT_CHECKED(Smi, flag, args[2]);
9395 return obj->LookupAccessor(name, flag->value() == 0);
9396}
9397
9398
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009399#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009400RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009401 ASSERT(args.length() == 0);
9402 return Execution::DebugBreakHelper();
9403}
9404
9405
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009406// Helper functions for wrapping and unwrapping stack frame ids.
9407static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009408 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009409 return Smi::FromInt(id >> 2);
9410}
9411
9412
9413static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9414 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9415}
9416
9417
9418// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009419// args[0]: debug event listener function to set or null or undefined for
9420// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009421// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009422RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009423 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009424 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9425 args[0]->IsUndefined() ||
9426 args[0]->IsNull());
9427 Handle<Object> callback = args.at<Object>(0);
9428 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009429 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009430
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009431 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009432}
9433
9434
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009435RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009436 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009437 isolate->stack_guard()->DebugBreak();
9438 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009439}
9440
9441
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009442static MaybeObject* DebugLookupResultValue(Heap* heap,
9443 Object* receiver,
9444 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009445 LookupResult* result,
9446 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009447 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009448 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009449 case NORMAL:
9450 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009451 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009452 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009453 }
9454 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009455 case FIELD:
9456 value =
9457 JSObject::cast(
9458 result->holder())->FastPropertyAt(result->GetFieldIndex());
9459 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009460 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009461 }
9462 return value;
9463 case CONSTANT_FUNCTION:
9464 return result->GetConstantFunction();
9465 case CALLBACKS: {
9466 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009467 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009468 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009469 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009470 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009471 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009472 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009473 maybe_value = heap->isolate()->pending_exception();
9474 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009475 if (caught_exception != NULL) {
9476 *caught_exception = true;
9477 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009478 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009479 }
9480 return value;
9481 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009482 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009483 }
9484 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009485 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009486 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009487 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009488 case CONSTANT_TRANSITION:
9489 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009490 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009491 default:
9492 UNREACHABLE();
9493 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009494 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009495 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009496}
9497
9498
ager@chromium.org32912102009-01-16 10:38:43 +00009499// Get debugger related details for an object property.
9500// args[0]: object holding property
9501// args[1]: name of the property
9502//
9503// The array returned contains the following information:
9504// 0: Property value
9505// 1: Property details
9506// 2: Property value is exception
9507// 3: Getter function if defined
9508// 4: Setter function if defined
9509// Items 2-4 are only filled if the property has either a getter or a setter
9510// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009511RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009512 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009513
9514 ASSERT(args.length() == 2);
9515
9516 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9517 CONVERT_ARG_CHECKED(String, name, 1);
9518
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009519 // Make sure to set the current context to the context before the debugger was
9520 // entered (if the debugger is entered). The reason for switching context here
9521 // is that for some property lookups (accessors and interceptors) callbacks
9522 // into the embedding application can occour, and the embedding application
9523 // could have the assumption that its own global context is the current
9524 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009525 SaveContext save(isolate);
9526 if (isolate->debug()->InDebugger()) {
9527 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009528 }
9529
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009530 // Skip the global proxy as it has no properties and always delegates to the
9531 // real global object.
9532 if (obj->IsJSGlobalProxy()) {
9533 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9534 }
9535
9536
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009537 // Check if the name is trivially convertible to an index and get the element
9538 // if so.
9539 uint32_t index;
9540 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009541 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009542 Object* element_or_char;
9543 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009544 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009545 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9546 return maybe_element_or_char;
9547 }
9548 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009549 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009550 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009551 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009552 }
9553
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009554 // Find the number of objects making up this.
9555 int length = LocalPrototypeChainLength(*obj);
9556
9557 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009558 Handle<JSObject> jsproto = obj;
9559 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009560 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009561 jsproto->LocalLookup(*name, &result);
9562 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009563 // LookupResult is not GC safe as it holds raw object pointers.
9564 // GC can happen later in this code so put the required fields into
9565 // local variables using handles when required for later use.
9566 PropertyType result_type = result.type();
9567 Handle<Object> result_callback_obj;
9568 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009569 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9570 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009571 }
9572 Smi* property_details = result.GetPropertyDetails().AsSmi();
9573 // DebugLookupResultValue can cause GC so details from LookupResult needs
9574 // to be copied to handles before this.
9575 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009576 Object* raw_value;
9577 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009578 DebugLookupResultValue(isolate->heap(), *obj, *name,
9579 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009580 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9581 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009582 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009583
9584 // If the callback object is a fixed array then it contains JavaScript
9585 // getter and/or setter.
9586 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9587 result_callback_obj->IsFixedArray();
9588 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009589 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009590 details->set(0, *value);
9591 details->set(1, property_details);
9592 if (hasJavaScriptAccessors) {
9593 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009594 caught_exception ? isolate->heap()->true_value()
9595 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009596 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9597 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9598 }
9599
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009600 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009601 }
9602 if (i < length - 1) {
9603 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9604 }
9605 }
9606
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009607 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009608}
9609
9610
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009611RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009612 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009613
9614 ASSERT(args.length() == 2);
9615
9616 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9617 CONVERT_ARG_CHECKED(String, name, 1);
9618
9619 LookupResult result;
9620 obj->Lookup(*name, &result);
9621 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009622 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009623 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009624 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009625}
9626
9627
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009628// Return the property type calculated from the property details.
9629// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009630RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009631 ASSERT(args.length() == 1);
9632 CONVERT_CHECKED(Smi, details, args[0]);
9633 PropertyType type = PropertyDetails(details).type();
9634 return Smi::FromInt(static_cast<int>(type));
9635}
9636
9637
9638// Return the property attribute calculated from the property details.
9639// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009640RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009641 ASSERT(args.length() == 1);
9642 CONVERT_CHECKED(Smi, details, args[0]);
9643 PropertyAttributes attributes = PropertyDetails(details).attributes();
9644 return Smi::FromInt(static_cast<int>(attributes));
9645}
9646
9647
9648// Return the property insertion index calculated from the property details.
9649// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009650RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009651 ASSERT(args.length() == 1);
9652 CONVERT_CHECKED(Smi, details, args[0]);
9653 int index = PropertyDetails(details).index();
9654 return Smi::FromInt(index);
9655}
9656
9657
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009658// Return property value from named interceptor.
9659// args[0]: object
9660// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009661RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009662 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009663 ASSERT(args.length() == 2);
9664 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9665 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9666 CONVERT_ARG_CHECKED(String, name, 1);
9667
9668 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009669 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009670}
9671
9672
9673// Return element value from indexed interceptor.
9674// args[0]: object
9675// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009676RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009677 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009678 ASSERT(args.length() == 2);
9679 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9680 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9681 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9682
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009683 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009684}
9685
9686
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009687RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009688 ASSERT(args.length() >= 1);
9689 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009690 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009691 if (isolate->debug()->break_id() == 0 ||
9692 break_id != isolate->debug()->break_id()) {
9693 return isolate->Throw(
9694 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009695 }
9696
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009697 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009698}
9699
9700
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009701RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009702 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009703 ASSERT(args.length() == 1);
9704
9705 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009706 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009707 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9708 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009709 if (!maybe_result->ToObject(&result)) return maybe_result;
9710 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009711
9712 // Count all frames which are relevant to debugging stack trace.
9713 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009714 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009715 if (id == StackFrame::NO_ID) {
9716 // If there is no JavaScript stack frame count is 0.
9717 return Smi::FromInt(0);
9718 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009719 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009720 return Smi::FromInt(n);
9721}
9722
9723
9724static const int kFrameDetailsFrameIdIndex = 0;
9725static const int kFrameDetailsReceiverIndex = 1;
9726static const int kFrameDetailsFunctionIndex = 2;
9727static const int kFrameDetailsArgumentCountIndex = 3;
9728static const int kFrameDetailsLocalCountIndex = 4;
9729static const int kFrameDetailsSourcePositionIndex = 5;
9730static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009731static const int kFrameDetailsAtReturnIndex = 7;
9732static const int kFrameDetailsDebuggerFrameIndex = 8;
9733static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009734
9735// Return an array with frame details
9736// args[0]: number: break id
9737// args[1]: number: frame index
9738//
9739// The array returned contains the following information:
9740// 0: Frame id
9741// 1: Receiver
9742// 2: Function
9743// 3: Argument count
9744// 4: Local count
9745// 5: Source position
9746// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009747// 7: Is at return
9748// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009749// Arguments name, value
9750// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009751// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009752RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009753 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009754 ASSERT(args.length() == 2);
9755
9756 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009757 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009758 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
9759 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009760 if (!maybe_check->ToObject(&check)) return maybe_check;
9761 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009762 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009763 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009764
9765 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009766 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009767 if (id == StackFrame::NO_ID) {
9768 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009769 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009770 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009771 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009772 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009773 for (; !it.done(); it.Advance()) {
9774 if (count == index) break;
9775 count++;
9776 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009777 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009778
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009779 bool is_optimized_frame =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009780 it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009781
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009782 // Traverse the saved contexts chain to find the active context for the
9783 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009784 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009785 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009786 save = save->prev();
9787 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009788 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009789
9790 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009791 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009792
9793 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009794 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009795 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009796
9797 // Check for constructor frame.
9798 bool constructor = it.frame()->IsConstructor();
9799
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009800 // Get scope info and read from it for local variable information.
9801 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009802 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009803 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009804
9805 // Get the context.
9806 Handle<Context> context(Context::cast(it.frame()->context()));
9807
9808 // Get the locals names and values into a temporary array.
9809 //
9810 // TODO(1240907): Hide compiler-introduced stack variables
9811 // (e.g. .result)? For users of the debugger, they will probably be
9812 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009813 Handle<FixedArray> locals =
9814 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009815
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009816 // Fill in the names of the locals.
9817 for (int i = 0; i < info.NumberOfLocals(); i++) {
9818 locals->set(i * 2, *info.LocalName(i));
9819 }
9820
9821 // Fill in the values of the locals.
9822 for (int i = 0; i < info.NumberOfLocals(); i++) {
9823 if (is_optimized_frame) {
9824 // If we are inspecting an optimized frame use undefined as the
9825 // value for all locals.
9826 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009827 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009828 // for locals in optimized frames.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009829 locals->set(i * 2 + 1, isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009830 } else if (i < info.number_of_stack_slots()) {
9831 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009832 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9833 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009834 // Traverse the context chain to the function context as all local
9835 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009836 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009837 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009838 context = Handle<Context>(context->previous());
9839 }
9840 ASSERT(context->is_function_context());
9841 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009842 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009843 }
9844 }
9845
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009846 // Check whether this frame is positioned at return. If not top
9847 // frame or if the frame is optimized it cannot be at a return.
9848 bool at_return = false;
9849 if (!is_optimized_frame && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009850 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009851 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009852
9853 // If positioned just before return find the value to be returned and add it
9854 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009855 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009856 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009857 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009858 Address internal_frame_sp = NULL;
9859 while (!it2.done()) {
9860 if (it2.frame()->is_internal()) {
9861 internal_frame_sp = it2.frame()->sp();
9862 } else {
9863 if (it2.frame()->is_java_script()) {
9864 if (it2.frame()->id() == it.frame()->id()) {
9865 // The internal frame just before the JavaScript frame contains the
9866 // value to return on top. A debug break at return will create an
9867 // internal frame to store the return value (eax/rax/r0) before
9868 // entering the debug break exit frame.
9869 if (internal_frame_sp != NULL) {
9870 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009871 Handle<Object>(Memory::Object_at(internal_frame_sp),
9872 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009873 break;
9874 }
9875 }
9876 }
9877
9878 // Indicate that the previous frame was not an internal frame.
9879 internal_frame_sp = NULL;
9880 }
9881 it2.Advance();
9882 }
9883 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009884
9885 // Now advance to the arguments adapter frame (if any). It contains all
9886 // the provided parameters whereas the function frame always have the number
9887 // of arguments matching the functions parameters. The rest of the
9888 // information (except for what is collected above) is the same.
9889 it.AdvanceToArgumentsFrame();
9890
9891 // Find the number of arguments to fill. At least fill the number of
9892 // parameters for the function and fill more if more parameters are provided.
9893 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009894 if (argument_count < it.frame()->ComputeParametersCount()) {
9895 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009896 }
9897
9898 // Calculate the size of the result.
9899 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009900 2 * (argument_count + info.NumberOfLocals()) +
9901 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009902 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009903
9904 // Add the frame id.
9905 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9906
9907 // Add the function (same as in function frame).
9908 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9909
9910 // Add the arguments count.
9911 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9912
9913 // Add the locals count
9914 details->set(kFrameDetailsLocalCountIndex,
9915 Smi::FromInt(info.NumberOfLocals()));
9916
9917 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009918 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009919 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9920 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009921 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009922 }
9923
9924 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009925 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009926
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009927 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009928 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009929
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009930 // Add information on whether this frame is invoked in the debugger context.
9931 details->set(kFrameDetailsDebuggerFrameIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009932 heap->ToBoolean(*save->context() ==
9933 *isolate->debug()->debug_context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009934
9935 // Fill the dynamic part.
9936 int details_index = kFrameDetailsFirstDynamicIndex;
9937
9938 // Add arguments name and value.
9939 for (int i = 0; i < argument_count; i++) {
9940 // Name of the argument.
9941 if (i < info.number_of_parameters()) {
9942 details->set(details_index++, *info.parameter_name(i));
9943 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009944 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009945 }
9946
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009947 // Parameter value. If we are inspecting an optimized frame, use
9948 // undefined as the value.
9949 //
9950 // TODO(3141533): We should be able to get the actual parameter
9951 // value for optimized frames.
9952 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009953 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009954 details->set(details_index++, it.frame()->GetParameter(i));
9955 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009956 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009957 }
9958 }
9959
9960 // Add locals name and value from the temporary copy from the function frame.
9961 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9962 details->set(details_index++, locals->get(i));
9963 }
9964
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009965 // Add the value being returned.
9966 if (at_return) {
9967 details->set(details_index++, *return_value);
9968 }
9969
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009970 // Add the receiver (same as in function frame).
9971 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9972 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009973 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009974 if (!receiver->IsJSObject()) {
9975 // If the receiver is NOT a JSObject we have hit an optimization
9976 // where a value object is not converted into a wrapped JS objects.
9977 // To hide this optimization from the debugger, we wrap the receiver
9978 // by creating correct wrapper object based on the calling frame's
9979 // global context.
9980 it.Advance();
9981 Handle<Context> calling_frames_global_context(
9982 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009983 receiver =
9984 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009985 }
9986 details->set(kFrameDetailsReceiverIndex, *receiver);
9987
9988 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009989 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009990}
9991
9992
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009993// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009994static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009995 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009996 Handle<SerializedScopeInfo> serialized_scope_info,
9997 ScopeInfo<>& scope_info,
9998 Handle<Context> context,
9999 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010000 // Fill all context locals to the context extension.
10001 for (int i = Context::MIN_CONTEXT_SLOTS;
10002 i < scope_info.number_of_context_slots();
10003 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010004 int context_index = serialized_scope_info->ContextSlotIndex(
10005 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010006
10007 // Don't include the arguments shadow (.arguments) context variable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010008 if (*scope_info.context_slot_name(i) !=
10009 isolate->heap()->arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010010 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010011 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010012 SetProperty(scope_object,
10013 scope_info.context_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010014 Handle<Object>(context->get(context_index), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010015 NONE,
10016 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010017 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010018 }
10019 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010020
10021 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010022}
10023
10024
10025// Create a plain JSObject which materializes the local scope for the specified
10026// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010027static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
10028 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010029 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010030 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010031 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10032 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010033
10034 // Allocate and initialize a JSObject with all the arguments, stack locals
10035 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010036 Handle<JSObject> local_scope =
10037 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010038
10039 // First fill all parameters.
10040 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010041 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010042 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010043 SetProperty(local_scope,
10044 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010045 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010046 NONE,
10047 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010048 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010049 }
10050
10051 // Second fill all stack locals.
10052 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010053 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010054 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010055 SetProperty(local_scope,
10056 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010057 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010058 NONE,
10059 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010060 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010061 }
10062
10063 // Third fill all context locals.
10064 Handle<Context> frame_context(Context::cast(frame->context()));
10065 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010066 if (!CopyContextLocalsToScopeObject(isolate,
10067 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010068 function_context, local_scope)) {
10069 return Handle<JSObject>();
10070 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010071
10072 // Finally copy any properties from the function context extension. This will
10073 // be variables introduced by eval.
10074 if (function_context->closure() == *function) {
10075 if (function_context->has_extension() &&
10076 !function_context->IsGlobalContext()) {
10077 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010078 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010079 for (int i = 0; i < keys->length(); i++) {
10080 // Names of variables introduced by eval are strings.
10081 ASSERT(keys->get(i)->IsString());
10082 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010083 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010084 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010085 SetProperty(local_scope,
10086 key,
10087 GetProperty(ext, key),
10088 NONE,
10089 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010090 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010091 }
10092 }
10093 }
10094 return local_scope;
10095}
10096
10097
10098// Create a plain JSObject which materializes the closure content for the
10099// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010100static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10101 Handle<Context> context) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010102 ASSERT(context->is_function_context());
10103
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010104 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010105 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10106 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010107
10108 // Allocate and initialize a JSObject with all the content of theis function
10109 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010110 Handle<JSObject> closure_scope =
10111 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010112
10113 // Check whether the arguments shadow object exists.
10114 int arguments_shadow_index =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010115 shared->scope_info()->ContextSlotIndex(
10116 isolate->heap()->arguments_shadow_symbol(), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010117 if (arguments_shadow_index >= 0) {
10118 // In this case all the arguments are available in the arguments shadow
10119 // object.
10120 Handle<JSObject> arguments_shadow(
10121 JSObject::cast(context->get(arguments_shadow_index)));
10122 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010123 // We don't expect exception-throwing getters on the arguments shadow.
10124 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010125 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010126 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010127 SetProperty(closure_scope,
10128 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010129 Handle<Object>(element, isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010130 NONE,
10131 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010132 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010133 }
10134 }
10135
10136 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010137 if (!CopyContextLocalsToScopeObject(isolate,
10138 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010139 context, closure_scope)) {
10140 return Handle<JSObject>();
10141 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010142
10143 // Finally copy any properties from the function context extension. This will
10144 // be variables introduced by eval.
10145 if (context->has_extension()) {
10146 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010147 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010148 for (int i = 0; i < keys->length(); i++) {
10149 // Names of variables introduced by eval are strings.
10150 ASSERT(keys->get(i)->IsString());
10151 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010152 RETURN_IF_EMPTY_HANDLE_VALUE(
10153 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010154 SetProperty(closure_scope,
10155 key,
10156 GetProperty(ext, key),
10157 NONE,
10158 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010159 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010160 }
10161 }
10162
10163 return closure_scope;
10164}
10165
10166
10167// Iterate over the actual scopes visible from a stack frame. All scopes are
10168// backed by an actual context except the local scope, which is inserted
10169// "artifically" in the context chain.
10170class ScopeIterator {
10171 public:
10172 enum ScopeType {
10173 ScopeTypeGlobal = 0,
10174 ScopeTypeLocal,
10175 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010176 ScopeTypeClosure,
10177 // Every catch block contains an implicit with block (its parameter is
10178 // a JSContextExtensionObject) that extends current scope with a variable
10179 // holding exception object. Such with blocks are treated as scopes of their
10180 // own type.
10181 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010182 };
10183
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010184 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
10185 : isolate_(isolate),
10186 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010187 function_(JSFunction::cast(frame->function())),
10188 context_(Context::cast(frame->context())),
10189 local_done_(false),
10190 at_local_(false) {
10191
10192 // Check whether the first scope is actually a local scope.
10193 if (context_->IsGlobalContext()) {
10194 // If there is a stack slot for .result then this local scope has been
10195 // created for evaluating top level code and it is not a real local scope.
10196 // Checking for the existence of .result seems fragile, but the scope info
10197 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010198 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010199 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010200 at_local_ = index < 0;
10201 } else if (context_->is_function_context()) {
10202 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010203 } else if (context_->closure() != *function_) {
10204 // The context_ is a with block from the outer function.
10205 ASSERT(context_->has_extension());
10206 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010207 }
10208 }
10209
10210 // More scopes?
10211 bool Done() { return context_.is_null(); }
10212
10213 // Move to the next scope.
10214 void Next() {
10215 // If at a local scope mark the local scope as passed.
10216 if (at_local_) {
10217 at_local_ = false;
10218 local_done_ = true;
10219
10220 // If the current context is not associated with the local scope the
10221 // current context is the next real scope, so don't move to the next
10222 // context in this case.
10223 if (context_->closure() != *function_) {
10224 return;
10225 }
10226 }
10227
10228 // The global scope is always the last in the chain.
10229 if (context_->IsGlobalContext()) {
10230 context_ = Handle<Context>();
10231 return;
10232 }
10233
10234 // Move to the next context.
10235 if (context_->is_function_context()) {
10236 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
10237 } else {
10238 context_ = Handle<Context>(context_->previous());
10239 }
10240
10241 // If passing the local scope indicate that the current scope is now the
10242 // local scope.
10243 if (!local_done_ &&
10244 (context_->IsGlobalContext() || (context_->is_function_context()))) {
10245 at_local_ = true;
10246 }
10247 }
10248
10249 // Return the type of the current scope.
10250 int Type() {
10251 if (at_local_) {
10252 return ScopeTypeLocal;
10253 }
10254 if (context_->IsGlobalContext()) {
10255 ASSERT(context_->global()->IsGlobalObject());
10256 return ScopeTypeGlobal;
10257 }
10258 if (context_->is_function_context()) {
10259 return ScopeTypeClosure;
10260 }
10261 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +000010262 // Current scope is either an explicit with statement or a with statement
10263 // implicitely generated for a catch block.
10264 // If the extension object here is a JSContextExtensionObject then
10265 // current with statement is one frome a catch block otherwise it's a
10266 // regular with statement.
10267 if (context_->extension()->IsJSContextExtensionObject()) {
10268 return ScopeTypeCatch;
10269 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010270 return ScopeTypeWith;
10271 }
10272
10273 // Return the JavaScript object with the content of the current scope.
10274 Handle<JSObject> ScopeObject() {
10275 switch (Type()) {
10276 case ScopeIterator::ScopeTypeGlobal:
10277 return Handle<JSObject>(CurrentContext()->global());
10278 break;
10279 case ScopeIterator::ScopeTypeLocal:
10280 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010281 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010282 break;
10283 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010284 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010285 // Return the with object.
10286 return Handle<JSObject>(CurrentContext()->extension());
10287 break;
10288 case ScopeIterator::ScopeTypeClosure:
10289 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010290 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010291 break;
10292 }
10293 UNREACHABLE();
10294 return Handle<JSObject>();
10295 }
10296
10297 // Return the context for this scope. For the local context there might not
10298 // be an actual context.
10299 Handle<Context> CurrentContext() {
10300 if (at_local_ && context_->closure() != *function_) {
10301 return Handle<Context>();
10302 }
10303 return context_;
10304 }
10305
10306#ifdef DEBUG
10307 // Debug print of the content of the current scope.
10308 void DebugPrint() {
10309 switch (Type()) {
10310 case ScopeIterator::ScopeTypeGlobal:
10311 PrintF("Global:\n");
10312 CurrentContext()->Print();
10313 break;
10314
10315 case ScopeIterator::ScopeTypeLocal: {
10316 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010317 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010318 scope_info.Print();
10319 if (!CurrentContext().is_null()) {
10320 CurrentContext()->Print();
10321 if (CurrentContext()->has_extension()) {
10322 Handle<JSObject> extension =
10323 Handle<JSObject>(CurrentContext()->extension());
10324 if (extension->IsJSContextExtensionObject()) {
10325 extension->Print();
10326 }
10327 }
10328 }
10329 break;
10330 }
10331
10332 case ScopeIterator::ScopeTypeWith: {
10333 PrintF("With:\n");
10334 Handle<JSObject> extension =
10335 Handle<JSObject>(CurrentContext()->extension());
10336 extension->Print();
10337 break;
10338 }
10339
ager@chromium.orga1645e22009-09-09 19:27:10 +000010340 case ScopeIterator::ScopeTypeCatch: {
10341 PrintF("Catch:\n");
10342 Handle<JSObject> extension =
10343 Handle<JSObject>(CurrentContext()->extension());
10344 extension->Print();
10345 break;
10346 }
10347
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010348 case ScopeIterator::ScopeTypeClosure: {
10349 PrintF("Closure:\n");
10350 CurrentContext()->Print();
10351 if (CurrentContext()->has_extension()) {
10352 Handle<JSObject> extension =
10353 Handle<JSObject>(CurrentContext()->extension());
10354 if (extension->IsJSContextExtensionObject()) {
10355 extension->Print();
10356 }
10357 }
10358 break;
10359 }
10360
10361 default:
10362 UNREACHABLE();
10363 }
10364 PrintF("\n");
10365 }
10366#endif
10367
10368 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010369 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010370 JavaScriptFrame* frame_;
10371 Handle<JSFunction> function_;
10372 Handle<Context> context_;
10373 bool local_done_;
10374 bool at_local_;
10375
10376 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10377};
10378
10379
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010380RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010381 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010382 ASSERT(args.length() == 2);
10383
10384 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010385 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010386 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10387 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010388 if (!maybe_check->ToObject(&check)) return maybe_check;
10389 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010390 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10391
10392 // Get the frame where the debugging is performed.
10393 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010394 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010395 JavaScriptFrame* frame = it.frame();
10396
10397 // Count the visible scopes.
10398 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010399 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010400 n++;
10401 }
10402
10403 return Smi::FromInt(n);
10404}
10405
10406
10407static const int kScopeDetailsTypeIndex = 0;
10408static const int kScopeDetailsObjectIndex = 1;
10409static const int kScopeDetailsSize = 2;
10410
10411// Return an array with scope details
10412// args[0]: number: break id
10413// args[1]: number: frame index
10414// args[2]: number: scope index
10415//
10416// The array returned contains the following information:
10417// 0: Scope type
10418// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010419RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010420 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010421 ASSERT(args.length() == 3);
10422
10423 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010424 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010425 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10426 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010427 if (!maybe_check->ToObject(&check)) return maybe_check;
10428 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010429 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10430 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10431
10432 // Get the frame where the debugging is performed.
10433 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010434 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010435 JavaScriptFrame* frame = frame_it.frame();
10436
10437 // Find the requested scope.
10438 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010439 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010440 for (; !it.Done() && n < index; it.Next()) {
10441 n++;
10442 }
10443 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010444 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010445 }
10446
10447 // Calculate the size of the result.
10448 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010449 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010450
10451 // Fill in scope details.
10452 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010453 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010454 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010455 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010456
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010457 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010458}
10459
10460
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010461RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010462 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010463 ASSERT(args.length() == 0);
10464
10465#ifdef DEBUG
10466 // Print the scopes for the top frame.
10467 StackFrameLocator locator;
10468 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010469 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010470 it.DebugPrint();
10471 }
10472#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010473 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010474}
10475
10476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010477RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010478 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010479 ASSERT(args.length() == 1);
10480
10481 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010482 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010483 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10484 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010485 if (!maybe_result->ToObject(&result)) return maybe_result;
10486 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010487
10488 // Count all archived V8 threads.
10489 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010490 for (ThreadState* thread =
10491 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010492 thread != NULL;
10493 thread = thread->Next()) {
10494 n++;
10495 }
10496
10497 // Total number of threads is current thread and archived threads.
10498 return Smi::FromInt(n + 1);
10499}
10500
10501
10502static const int kThreadDetailsCurrentThreadIndex = 0;
10503static const int kThreadDetailsThreadIdIndex = 1;
10504static const int kThreadDetailsSize = 2;
10505
10506// Return an array with thread details
10507// args[0]: number: break id
10508// args[1]: number: thread index
10509//
10510// The array returned contains the following information:
10511// 0: Is current thread?
10512// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010513RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010514 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010515 ASSERT(args.length() == 2);
10516
10517 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010518 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010519 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10520 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010521 if (!maybe_check->ToObject(&check)) return maybe_check;
10522 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010523 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10524
10525 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010526 Handle<FixedArray> details =
10527 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010528
10529 // Thread index 0 is current thread.
10530 if (index == 0) {
10531 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010532 details->set(kThreadDetailsCurrentThreadIndex,
10533 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010534 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010535 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010536 } else {
10537 // Find the thread with the requested index.
10538 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010539 ThreadState* thread =
10540 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010541 while (index != n && thread != NULL) {
10542 thread = thread->Next();
10543 n++;
10544 }
10545 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010546 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010547 }
10548
10549 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010550 details->set(kThreadDetailsCurrentThreadIndex,
10551 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010552 details->set(kThreadDetailsThreadIdIndex,
10553 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010554 }
10555
10556 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010557 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010558}
10559
10560
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010561// Sets the disable break state
10562// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010563RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010564 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010565 ASSERT(args.length() == 1);
10566 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010567 isolate->debug()->set_disable_break(disable_break);
10568 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010569}
10570
10571
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010572RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010573 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010574 ASSERT(args.length() == 1);
10575
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010576 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10577 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010578 // Find the number of break points
10579 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010580 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010581 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010582 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010583 Handle<FixedArray>::cast(break_locations));
10584}
10585
10586
10587// Set a break point in a function
10588// args[0]: function
10589// args[1]: number: break source position (within the function source)
10590// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010591RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010592 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010593 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010594 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10595 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010596 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10597 RUNTIME_ASSERT(source_position >= 0);
10598 Handle<Object> break_point_object_arg = args.at<Object>(2);
10599
10600 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010601 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10602 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010603
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010604 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010605}
10606
10607
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010608Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10609 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010610 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010611 // Iterate the heap looking for SharedFunctionInfo generated from the
10612 // script. The inner most SharedFunctionInfo containing the source position
10613 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010614 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010615 // which is found is not compiled it is compiled and the heap is iterated
10616 // again as the compilation might create inner functions from the newly
10617 // compiled function and the actual requested break point might be in one of
10618 // these functions.
10619 bool done = false;
10620 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010621 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010622 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010623 while (!done) {
10624 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010625 for (HeapObject* obj = iterator.next();
10626 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010627 if (obj->IsSharedFunctionInfo()) {
10628 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10629 if (shared->script() == *script) {
10630 // If the SharedFunctionInfo found has the requested script data and
10631 // contains the source position it is a candidate.
10632 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010633 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010634 start_position = shared->start_position();
10635 }
10636 if (start_position <= position &&
10637 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010638 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010639 // candidate this is the new candidate.
10640 if (target.is_null()) {
10641 target_start_position = start_position;
10642 target = shared;
10643 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010644 if (target_start_position == start_position &&
10645 shared->end_position() == target->end_position()) {
10646 // If a top-level function contain only one function
10647 // declartion the source for the top-level and the function is
10648 // the same. In that case prefer the non top-level function.
10649 if (!shared->is_toplevel()) {
10650 target_start_position = start_position;
10651 target = shared;
10652 }
10653 } else if (target_start_position <= start_position &&
10654 shared->end_position() <= target->end_position()) {
10655 // This containment check includes equality as a function inside
10656 // a top-level function can share either start or end position
10657 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010658 target_start_position = start_position;
10659 target = shared;
10660 }
10661 }
10662 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010663 }
10664 }
10665 }
10666
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010667 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010668 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010669 }
10670
10671 // If the candidate found is compiled we are done. NOTE: when lazy
10672 // compilation of inner functions is introduced some additional checking
10673 // needs to be done here to compile inner functions.
10674 done = target->is_compiled();
10675 if (!done) {
10676 // If the candidate is not compiled compile it to reveal any inner
10677 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010678 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010679 }
10680 }
10681
10682 return *target;
10683}
10684
10685
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010686// Changes the state of a break point in a script and returns source position
10687// where break point was set. NOTE: Regarding performance see the NOTE for
10688// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010689// args[0]: script to set break point in
10690// args[1]: number: break source position (within the script source)
10691// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010692RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010693 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010694 ASSERT(args.length() == 3);
10695 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10696 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10697 RUNTIME_ASSERT(source_position >= 0);
10698 Handle<Object> break_point_object_arg = args.at<Object>(2);
10699
10700 // Get the script from the script wrapper.
10701 RUNTIME_ASSERT(wrapper->value()->IsScript());
10702 Handle<Script> script(Script::cast(wrapper->value()));
10703
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010704 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010705 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010706 if (!result->IsUndefined()) {
10707 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10708 // Find position within function. The script position might be before the
10709 // source position of the first function.
10710 int position;
10711 if (shared->start_position() > source_position) {
10712 position = 0;
10713 } else {
10714 position = source_position - shared->start_position();
10715 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010716 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010717 position += shared->start_position();
10718 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010719 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010720 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010721}
10722
10723
10724// Clear a break point
10725// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010726RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010727 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010728 ASSERT(args.length() == 1);
10729 Handle<Object> break_point_object_arg = args.at<Object>(0);
10730
10731 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010732 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010733
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010734 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010735}
10736
10737
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010738// Change the state of break on exceptions.
10739// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10740// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010741RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010742 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010743 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010744 RUNTIME_ASSERT(args[0]->IsNumber());
10745 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010746
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010747 // If the number doesn't match an enum value, the ChangeBreakOnException
10748 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010749 ExceptionBreakType type =
10750 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010751 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010752 isolate->debug()->ChangeBreakOnException(type, enable);
10753 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010754}
10755
10756
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010757// Returns the state of break on exceptions
10758// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010759RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010760 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010761 ASSERT(args.length() == 1);
10762 RUNTIME_ASSERT(args[0]->IsNumber());
10763
10764 ExceptionBreakType type =
10765 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010766 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010767 return Smi::FromInt(result);
10768}
10769
10770
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010771// Prepare for stepping
10772// args[0]: break id for checking execution state
10773// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010774// args[2]: number of times to perform the step, for step out it is the number
10775// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010776RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010777 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010778 ASSERT(args.length() == 3);
10779 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010780 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010781 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10782 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010783 if (!maybe_check->ToObject(&check)) return maybe_check;
10784 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010785 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010786 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010787 }
10788
10789 // Get the step action and check validity.
10790 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10791 if (step_action != StepIn &&
10792 step_action != StepNext &&
10793 step_action != StepOut &&
10794 step_action != StepInMin &&
10795 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010796 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010797 }
10798
10799 // Get the number of steps.
10800 int step_count = NumberToInt32(args[2]);
10801 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010802 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010803 }
10804
ager@chromium.orga1645e22009-09-09 19:27:10 +000010805 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010806 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010807
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010808 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010809 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
10810 step_count);
10811 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010812}
10813
10814
10815// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010816RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010817 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010818 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010819 isolate->debug()->ClearStepping();
10820 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010821}
10822
10823
10824// Creates a copy of the with context chain. The copy of the context chain is
10825// is linked to the function context supplied.
10826static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10827 Handle<Context> function_context) {
10828 // At the bottom of the chain. Return the function context to link to.
10829 if (context_chain->is_function_context()) {
10830 return function_context;
10831 }
10832
10833 // Recursively copy the with contexts.
10834 Handle<Context> previous(context_chain->previous());
10835 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
danno@chromium.org160a7b02011-04-18 15:51:38 +000010836 Handle<Context> context = CopyWithContextChain(previous, function_context);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010837 return context->GetIsolate()->factory()->NewWithContext(
10838 context, extension, context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010839}
10840
10841
10842// Helper function to find or create the arguments object for
10843// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010844static Handle<Object> GetArgumentsObject(Isolate* isolate,
10845 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010846 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010847 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010848 const ScopeInfo<>* sinfo,
10849 Handle<Context> function_context) {
10850 // Try to find the value of 'arguments' to pass as parameter. If it is not
10851 // found (that is the debugged function does not reference 'arguments' and
10852 // does not support eval) then create an 'arguments' object.
10853 int index;
10854 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010855 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010856 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010857 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010858 }
10859 }
10860
10861 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010862 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
10863 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010864 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010865 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010866 }
10867 }
10868
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010869 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010870 Handle<JSObject> arguments =
10871 isolate->factory()->NewArgumentsObject(function, length);
10872 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010873
10874 AssertNoAllocation no_gc;
10875 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010876 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010877 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010878 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010879 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010880 return arguments;
10881}
10882
10883
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010884static const char kSourceStr[] =
10885 "(function(arguments,__source__){return eval(__source__);})";
10886
10887
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010888// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010889// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010890// extension part has all the parameters and locals of the function on the
10891// stack frame. A function which calls eval with the code to evaluate is then
10892// compiled in this context and called in this context. As this context
10893// replaces the context of the function on the stack frame a new (empty)
10894// function is created as well to be used as the closure for the context.
10895// This function and the context acts as replacements for the function on the
10896// stack frame presenting the same view of the values of parameters and
10897// local variables as if the piece of JavaScript was evaluated at the point
10898// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010899RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010900 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010901
10902 // Check the execution state and decode arguments frame and source to be
10903 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010904 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010905 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010906 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10907 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010908 if (!maybe_check_result->ToObject(&check_result)) {
10909 return maybe_check_result;
10910 }
10911 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010912 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10913 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010914 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010915 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010916
10917 // Handle the processing of break.
10918 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010919
10920 // Get the frame where the debugging is performed.
10921 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010922 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010923 JavaScriptFrame* frame = it.frame();
10924 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010925 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010926 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010927
10928 // Traverse the saved contexts chain to find the active context for the
10929 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010930 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010931 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010932 save = save->prev();
10933 }
10934 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010935 SaveContext savex(isolate);
10936 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010937
10938 // Create the (empty) function replacing the function on the stack frame for
10939 // the purpose of evaluating in the context created below. It is important
10940 // that this function does not describe any parameters and local variables
10941 // in the context. If it does then this will cause problems with the lookup
10942 // in Context::Lookup, where context slots for parameters and local variables
10943 // are looked at before the extension object.
10944 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010945 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
10946 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010947 go_between->set_context(function->context());
10948#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010949 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010950 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10951 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10952#endif
10953
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010954 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010955 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
10956 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010957
10958 // Allocate a new context for the debug evaluation and set the extension
10959 // object build.
10960 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010961 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
10962 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010963 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010964 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010965 Handle<Context> frame_context(Context::cast(frame->context()));
10966 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010967 context = CopyWithContextChain(frame_context, context);
10968
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010969 if (additional_context->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010970 context = isolate->factory()->NewWithContext(context,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010971 Handle<JSObject>::cast(additional_context), false);
10972 }
10973
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010974 // Wrap the evaluation statement in a new function compiled in the newly
10975 // created context. The function has one parameter which has to be called
10976 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000010977 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010978 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010979
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010980 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010981 isolate->factory()->NewStringFromAscii(
10982 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010983
10984 // Currently, the eval code will be executed in non-strict mode,
10985 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010986 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010987 Compiler::CompileEval(function_source,
10988 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010989 context->IsGlobalContext(),
10990 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010991 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010992 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010993 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010994
10995 // Invoke the result of the compilation to get the evaluation function.
10996 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010997 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010998 Handle<Object> evaluation_function =
10999 Execution::Call(compiled_function, receiver, 0, NULL,
11000 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011001 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011002
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011003 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
11004 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011005 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011006
11007 // Invoke the evaluation function and return the result.
11008 const int argc = 2;
11009 Object** argv[argc] = { arguments.location(),
11010 Handle<Object>::cast(source).location() };
11011 Handle<Object> result =
11012 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11013 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011014 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011015
11016 // Skip the global proxy as it has no properties and always delegates to the
11017 // real global object.
11018 if (result->IsJSGlobalProxy()) {
11019 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11020 }
11021
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011022 return *result;
11023}
11024
11025
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011026RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011027 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011028
11029 // Check the execution state and decode arguments frame and source to be
11030 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011031 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011032 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011033 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11034 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011035 if (!maybe_check_result->ToObject(&check_result)) {
11036 return maybe_check_result;
11037 }
11038 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011039 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011040 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011041 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011042
11043 // Handle the processing of break.
11044 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011045
11046 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011047 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011048 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011049 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011050 top = top->prev();
11051 }
11052 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011053 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011054 }
11055
11056 // Get the global context now set to the top context from before the
11057 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011058 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011059
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011060 bool is_global = true;
11061
11062 if (additional_context->IsJSObject()) {
11063 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011064 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11065 isolate->factory()->empty_string(),
11066 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011067 go_between->set_context(*context);
11068 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011069 isolate->factory()->NewFunctionContext(
11070 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011071 context->set_extension(JSObject::cast(*additional_context));
11072 is_global = false;
11073 }
11074
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011075 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011076 // Currently, the eval code will be executed in non-strict mode,
11077 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011078 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011079 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011080 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011081 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011082 Handle<JSFunction>(
11083 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11084 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011085
11086 // Invoke the result of the compilation to get the evaluation function.
11087 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011088 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011089 Handle<Object> result =
11090 Execution::Call(compiled_function, receiver, 0, NULL,
11091 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011092 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011093 return *result;
11094}
11095
11096
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011097RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011098 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011099 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011100
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011101 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011102 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011103
11104 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011105 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011106 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11107 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11108 // because using
11109 // instances->set(i, *GetScriptWrapper(script))
11110 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11111 // already have deferenced the instances handle.
11112 Handle<JSValue> wrapper = GetScriptWrapper(script);
11113 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011114 }
11115
11116 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011117 Handle<JSObject> result =
11118 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011119 Handle<JSArray>::cast(result)->SetContent(*instances);
11120 return *result;
11121}
11122
11123
11124// Helper function used by Runtime_DebugReferencedBy below.
11125static int DebugReferencedBy(JSObject* target,
11126 Object* instance_filter, int max_references,
11127 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011128 JSFunction* arguments_function) {
11129 NoHandleAllocation ha;
11130 AssertNoAllocation no_alloc;
11131
11132 // Iterate the heap.
11133 int count = 0;
11134 JSObject* last = NULL;
11135 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011136 HeapObject* heap_obj = NULL;
11137 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011138 (max_references == 0 || count < max_references)) {
11139 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011140 if (heap_obj->IsJSObject()) {
11141 // Skip context extension objects and argument arrays as these are
11142 // checked in the context of functions using them.
11143 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011144 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011145 obj->map()->constructor() == arguments_function) {
11146 continue;
11147 }
11148
11149 // Check if the JS object has a reference to the object looked for.
11150 if (obj->ReferencesObject(target)) {
11151 // Check instance filter if supplied. This is normally used to avoid
11152 // references from mirror objects (see Runtime_IsInPrototypeChain).
11153 if (!instance_filter->IsUndefined()) {
11154 Object* V = obj;
11155 while (true) {
11156 Object* prototype = V->GetPrototype();
11157 if (prototype->IsNull()) {
11158 break;
11159 }
11160 if (instance_filter == prototype) {
11161 obj = NULL; // Don't add this object.
11162 break;
11163 }
11164 V = prototype;
11165 }
11166 }
11167
11168 if (obj != NULL) {
11169 // Valid reference found add to instance array if supplied an update
11170 // count.
11171 if (instances != NULL && count < instances_size) {
11172 instances->set(count, obj);
11173 }
11174 last = obj;
11175 count++;
11176 }
11177 }
11178 }
11179 }
11180
11181 // Check for circular reference only. This can happen when the object is only
11182 // referenced from mirrors and has a circular reference in which case the
11183 // object is not really alive and would have been garbage collected if not
11184 // referenced from the mirror.
11185 if (count == 1 && last == target) {
11186 count = 0;
11187 }
11188
11189 // Return the number of referencing objects found.
11190 return count;
11191}
11192
11193
11194// Scan the heap for objects with direct references to an object
11195// args[0]: the object to find references to
11196// args[1]: constructor function for instances to exclude (Mirror)
11197// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011198RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011199 ASSERT(args.length() == 3);
11200
11201 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011202 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011203
11204 // Check parameters.
11205 CONVERT_CHECKED(JSObject, target, args[0]);
11206 Object* instance_filter = args[1];
11207 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11208 instance_filter->IsJSObject());
11209 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11210 RUNTIME_ASSERT(max_references >= 0);
11211
11212 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011213 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011214 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011215 JSFunction* arguments_function =
11216 JSFunction::cast(arguments_boilerplate->map()->constructor());
11217
11218 // Get the number of referencing objects.
11219 int count;
11220 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011221 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011222
11223 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011224 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011225 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011226 if (!maybe_object->ToObject(&object)) return maybe_object;
11227 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011228 FixedArray* instances = FixedArray::cast(object);
11229
11230 // Fill the referencing objects.
11231 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011232 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011233
11234 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011235 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011236 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11237 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011238 if (!maybe_result->ToObject(&result)) return maybe_result;
11239 }
11240 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011241 return result;
11242}
11243
11244
11245// Helper function used by Runtime_DebugConstructedBy below.
11246static int DebugConstructedBy(JSFunction* constructor, int max_references,
11247 FixedArray* instances, int instances_size) {
11248 AssertNoAllocation no_alloc;
11249
11250 // Iterate the heap.
11251 int count = 0;
11252 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011253 HeapObject* heap_obj = NULL;
11254 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011255 (max_references == 0 || count < max_references)) {
11256 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011257 if (heap_obj->IsJSObject()) {
11258 JSObject* obj = JSObject::cast(heap_obj);
11259 if (obj->map()->constructor() == constructor) {
11260 // Valid reference found add to instance array if supplied an update
11261 // count.
11262 if (instances != NULL && count < instances_size) {
11263 instances->set(count, obj);
11264 }
11265 count++;
11266 }
11267 }
11268 }
11269
11270 // Return the number of referencing objects found.
11271 return count;
11272}
11273
11274
11275// Scan the heap for objects constructed by a specific function.
11276// args[0]: the constructor to find instances of
11277// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011278RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011279 ASSERT(args.length() == 2);
11280
11281 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011282 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011283
11284 // Check parameters.
11285 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11286 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11287 RUNTIME_ASSERT(max_references >= 0);
11288
11289 // Get the number of referencing objects.
11290 int count;
11291 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11292
11293 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011294 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011295 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011296 if (!maybe_object->ToObject(&object)) return maybe_object;
11297 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011298 FixedArray* instances = FixedArray::cast(object);
11299
11300 // Fill the referencing objects.
11301 count = DebugConstructedBy(constructor, max_references, instances, count);
11302
11303 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011304 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011305 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11306 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011307 if (!maybe_result->ToObject(&result)) return maybe_result;
11308 }
11309 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011310 return result;
11311}
11312
11313
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011314// Find the effective prototype object as returned by __proto__.
11315// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011316RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011317 ASSERT(args.length() == 1);
11318
11319 CONVERT_CHECKED(JSObject, obj, args[0]);
11320
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011321 // Use the __proto__ accessor.
11322 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011323}
11324
11325
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011326RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011327 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011328 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011329 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011330}
11331
11332
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011333RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011334#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011335 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011336 ASSERT(args.length() == 1);
11337 // Get the function and make sure it is compiled.
11338 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011339 Handle<SharedFunctionInfo> shared(func->shared());
11340 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011341 return Failure::Exception();
11342 }
11343 func->code()->PrintLn();
11344#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011345 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011346}
ager@chromium.org9085a012009-05-11 19:22:57 +000011347
11348
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011349RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011350#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011351 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011352 ASSERT(args.length() == 1);
11353 // Get the function and make sure it is compiled.
11354 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011355 Handle<SharedFunctionInfo> shared(func->shared());
11356 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011357 return Failure::Exception();
11358 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011359 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011360#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011361 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011362}
11363
11364
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011365RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011366 NoHandleAllocation ha;
11367 ASSERT(args.length() == 1);
11368
11369 CONVERT_CHECKED(JSFunction, f, args[0]);
11370 return f->shared()->inferred_name();
11371}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011372
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011373
11374static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011375 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011376 AssertNoAllocation no_allocations;
11377
11378 int counter = 0;
11379 int buffer_size = buffer->length();
11380 HeapIterator iterator;
11381 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11382 ASSERT(obj != NULL);
11383 if (!obj->IsSharedFunctionInfo()) {
11384 continue;
11385 }
11386 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11387 if (shared->script() != script) {
11388 continue;
11389 }
11390 if (counter < buffer_size) {
11391 buffer->set(counter, shared);
11392 }
11393 counter++;
11394 }
11395 return counter;
11396}
11397
11398// For a script finds all SharedFunctionInfo's in the heap that points
11399// to this script. Returns JSArray of SharedFunctionInfo wrapped
11400// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011401RUNTIME_FUNCTION(MaybeObject*,
11402 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011403 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011404 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011405 CONVERT_CHECKED(JSValue, script_value, args[0]);
11406
11407 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11408
11409 const int kBufferSize = 32;
11410
11411 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011412 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011413 int number = FindSharedFunctionInfosForScript(*script, *array);
11414 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011415 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011416 FindSharedFunctionInfosForScript(*script, *array);
11417 }
11418
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011419 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011420 result->set_length(Smi::FromInt(number));
11421
11422 LiveEdit::WrapSharedFunctionInfos(result);
11423
11424 return *result;
11425}
11426
11427// For a script calculates compilation information about all its functions.
11428// The script source is explicitly specified by the second argument.
11429// The source of the actual script is not used, however it is important that
11430// all generated code keeps references to this particular instance of script.
11431// Returns a JSArray of compilation infos. The array is ordered so that
11432// each function with all its descendant is always stored in a continues range
11433// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011434RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011435 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011436 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011437 CONVERT_CHECKED(JSValue, script, args[0]);
11438 CONVERT_ARG_CHECKED(String, source, 1);
11439 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11440
11441 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11442
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011443 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011444 return Failure::Exception();
11445 }
11446
11447 return result;
11448}
11449
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011450// Changes the source of the script to a new_source.
11451// If old_script_name is provided (i.e. is a String), also creates a copy of
11452// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011453RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011454 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011455 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011456 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11457 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011458 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011459
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011460 CONVERT_CHECKED(Script, original_script_pointer,
11461 original_script_value->value());
11462 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011463
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011464 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11465 new_source,
11466 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011467
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011468 if (old_script->IsScript()) {
11469 Handle<Script> script_handle(Script::cast(old_script));
11470 return *(GetScriptWrapper(script_handle));
11471 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011472 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011473 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011474}
11475
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011477RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011478 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011479 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011480 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11481 return LiveEdit::FunctionSourceUpdated(shared_info);
11482}
11483
11484
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011485// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011486RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
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_ARG_CHECKED(JSArray, new_compile_info, 0);
11490 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11491
ager@chromium.orgac091b72010-05-05 07:34:42 +000011492 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011493}
11494
11495// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011496RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011497 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011498 HandleScope scope(isolate);
11499 Handle<Object> function_object(args[0], isolate);
11500 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011501
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011502 if (function_object->IsJSValue()) {
11503 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11504 if (script_object->IsJSValue()) {
11505 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011506 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011507 }
11508
11509 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11510 } else {
11511 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11512 // and we check it in this function.
11513 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011514
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011515 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011516}
11517
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011518
11519// In a code of a parent function replaces original function as embedded object
11520// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011521RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011522 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011523 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011524
11525 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11526 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11527 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11528
11529 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11530 subst_wrapper);
11531
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011532 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011533}
11534
11535
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011536// Updates positions of a shared function info (first parameter) according
11537// to script source change. Text change is described in second parameter as
11538// array of groups of 3 numbers:
11539// (change_begin, change_end, change_end_new_position).
11540// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011541RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011542 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011543 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011544 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11545 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11546
ager@chromium.orgac091b72010-05-05 07:34:42 +000011547 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011548}
11549
11550
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011551// For array of SharedFunctionInfo's (each wrapped in JSValue)
11552// checks that none of them have activations on stacks (of any thread).
11553// Returns array of the same length with corresponding results of
11554// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011555RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011556 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011557 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011558 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011559 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011560
ager@chromium.org357bf652010-04-12 11:30:10 +000011561 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011562}
11563
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011564// Compares 2 strings line-by-line, then token-wise and returns diff in form
11565// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11566// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011567RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011568 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011569 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011570 CONVERT_ARG_CHECKED(String, s1, 0);
11571 CONVERT_ARG_CHECKED(String, s2, 1);
11572
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011573 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011574}
11575
11576
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011577// A testing entry. Returns statement position which is the closest to
11578// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011579RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011580 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011581 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011582 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11583 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11584
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011585 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011586
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011587 if (code->kind() != Code::FUNCTION &&
11588 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011589 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011590 }
11591
11592 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011593 int closest_pc = 0;
11594 int distance = kMaxInt;
11595 while (!it.done()) {
11596 int statement_position = static_cast<int>(it.rinfo()->data());
11597 // Check if this break point is closer that what was previously found.
11598 if (source_position <= statement_position &&
11599 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011600 closest_pc =
11601 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011602 distance = statement_position - source_position;
11603 // Check whether we can't get any closer.
11604 if (distance == 0) break;
11605 }
11606 it.next();
11607 }
11608
11609 return Smi::FromInt(closest_pc);
11610}
11611
11612
ager@chromium.org357bf652010-04-12 11:30:10 +000011613// Calls specified function with or without entering the debugger.
11614// This is used in unit tests to run code as if debugger is entered or simply
11615// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011616RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011617 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011618 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011619 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11620 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11621
11622 Handle<Object> result;
11623 bool pending_exception;
11624 {
11625 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011626 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011627 &pending_exception);
11628 } else {
11629 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011630 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011631 &pending_exception);
11632 }
11633 }
11634 if (!pending_exception) {
11635 return *result;
11636 } else {
11637 return Failure::Exception();
11638 }
11639}
11640
11641
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011642// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011643RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011644 CONVERT_CHECKED(String, arg, args[0]);
11645 SmartPointer<char> flags =
11646 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11647 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011648 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011649}
11650
11651
11652// Performs a GC.
11653// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011654RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011655 isolate->heap()->CollectAllGarbage(true);
11656 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011657}
11658
11659
11660// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011661RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011662 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011663 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011664 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011665 }
11666 return Smi::FromInt(usage);
11667}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011668
11669
11670// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011671RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011672#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011673 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011674#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011675 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011676#endif
11677}
11678
11679
11680// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011681RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011682#ifdef LIVE_OBJECT_LIST
11683 return LiveObjectList::Capture();
11684#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011685 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011686#endif
11687}
11688
11689
11690// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011691RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011692#ifdef LIVE_OBJECT_LIST
11693 CONVERT_SMI_CHECKED(id, args[0]);
11694 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011695 return success ? isolate->heap()->true_value() :
11696 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011697#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011698 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011699#endif
11700}
11701
11702
11703// Generates the response to a debugger request for a dump of the objects
11704// contained in the difference between the captured live object lists
11705// specified by id1 and id2.
11706// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11707// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011708RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011709#ifdef LIVE_OBJECT_LIST
11710 HandleScope scope;
11711 CONVERT_SMI_CHECKED(id1, args[0]);
11712 CONVERT_SMI_CHECKED(id2, args[1]);
11713 CONVERT_SMI_CHECKED(start, args[2]);
11714 CONVERT_SMI_CHECKED(count, args[3]);
11715 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11716 EnterDebugger enter_debugger;
11717 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11718#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011719 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011720#endif
11721}
11722
11723
11724// Gets the specified object as requested by the debugger.
11725// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011726RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011727#ifdef LIVE_OBJECT_LIST
11728 CONVERT_SMI_CHECKED(obj_id, args[0]);
11729 Object* result = LiveObjectList::GetObj(obj_id);
11730 return result;
11731#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011732 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011733#endif
11734}
11735
11736
11737// Gets the obj id for the specified address if valid.
11738// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011739RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011740#ifdef LIVE_OBJECT_LIST
11741 HandleScope scope;
11742 CONVERT_ARG_CHECKED(String, address, 0);
11743 Object* result = LiveObjectList::GetObjId(address);
11744 return result;
11745#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011746 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011747#endif
11748}
11749
11750
11751// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011752RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011753#ifdef LIVE_OBJECT_LIST
11754 HandleScope scope;
11755 CONVERT_SMI_CHECKED(obj_id, args[0]);
11756 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11757 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11758 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11759 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11760 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11761
11762 Handle<JSObject> instance_filter;
11763 if (args[1]->IsJSObject()) {
11764 instance_filter = args.at<JSObject>(1);
11765 }
11766 bool verbose = false;
11767 if (args[2]->IsBoolean()) {
11768 verbose = args[2]->IsTrue();
11769 }
11770 int start = 0;
11771 if (args[3]->IsSmi()) {
11772 start = Smi::cast(args[3])->value();
11773 }
11774 int limit = Smi::kMaxValue;
11775 if (args[4]->IsSmi()) {
11776 limit = Smi::cast(args[4])->value();
11777 }
11778
11779 return LiveObjectList::GetObjRetainers(obj_id,
11780 instance_filter,
11781 verbose,
11782 start,
11783 limit,
11784 filter_obj);
11785#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011786 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011787#endif
11788}
11789
11790
11791// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011792RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011793#ifdef LIVE_OBJECT_LIST
11794 HandleScope scope;
11795 CONVERT_SMI_CHECKED(obj_id1, args[0]);
11796 CONVERT_SMI_CHECKED(obj_id2, args[1]);
11797 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11798
11799 Handle<JSObject> instance_filter;
11800 if (args[2]->IsJSObject()) {
11801 instance_filter = args.at<JSObject>(2);
11802 }
11803
11804 Object* result =
11805 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11806 return result;
11807#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011808 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011809#endif
11810}
11811
11812
11813// Generates the response to a debugger request for a list of all
11814// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011815RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011816#ifdef LIVE_OBJECT_LIST
11817 CONVERT_SMI_CHECKED(start, args[0]);
11818 CONVERT_SMI_CHECKED(count, args[1]);
11819 return LiveObjectList::Info(start, count);
11820#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011821 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011822#endif
11823}
11824
11825
11826// Gets a dump of the specified object as requested by the debugger.
11827// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011828RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011829#ifdef LIVE_OBJECT_LIST
11830 HandleScope scope;
11831 CONVERT_SMI_CHECKED(obj_id, args[0]);
11832 Object* result = LiveObjectList::PrintObj(obj_id);
11833 return result;
11834#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011835 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011836#endif
11837}
11838
11839
11840// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011841RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011842#ifdef LIVE_OBJECT_LIST
11843 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011844 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011845#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011846 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011847#endif
11848}
11849
11850
11851// Generates the response to a debugger request for a summary of the types
11852// of objects in the difference between the captured live object lists
11853// specified by id1 and id2.
11854// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11855// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011856RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011857#ifdef LIVE_OBJECT_LIST
11858 HandleScope scope;
11859 CONVERT_SMI_CHECKED(id1, args[0]);
11860 CONVERT_SMI_CHECKED(id2, args[1]);
11861 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11862
11863 EnterDebugger enter_debugger;
11864 return LiveObjectList::Summarize(id1, id2, filter_obj);
11865#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011866 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011867#endif
11868}
11869
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011870#endif // ENABLE_DEBUGGER_SUPPORT
11871
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011872
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011873#ifdef ENABLE_LOGGING_AND_PROFILING
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011874RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011875 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011876 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011877
11878 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011879 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11880 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011881 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011882}
11883
11884
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011885RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011886 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011887 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011888
11889 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011890 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11891 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011892 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011893}
11894
11895#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011896
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011897// Finds the script object from the script data. NOTE: This operation uses
11898// heap traversal to find the function generated for the source position
11899// for the requested break point. For lazily compiled functions several heap
11900// traversals might be required rendering this operation as a rather slow
11901// operation. However for setting break points which is normally done through
11902// some kind of user interaction the performance is not crucial.
11903static Handle<Object> Runtime_GetScriptFromScriptName(
11904 Handle<String> script_name) {
11905 // Scan the heap for Script objects to find the script with the requested
11906 // script data.
11907 Handle<Script> script;
11908 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011909 HeapObject* obj = NULL;
11910 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011911 // If a script is found check if it has the script data requested.
11912 if (obj->IsScript()) {
11913 if (Script::cast(obj)->name()->IsString()) {
11914 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11915 script = Handle<Script>(Script::cast(obj));
11916 }
11917 }
11918 }
11919 }
11920
11921 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011922 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011923
11924 // Return the script found.
11925 return GetScriptWrapper(script);
11926}
11927
11928
11929// Get the script object from script data. NOTE: Regarding performance
11930// see the NOTE for GetScriptFromScriptData.
11931// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011932RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011933 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011934
11935 ASSERT(args.length() == 1);
11936
11937 CONVERT_CHECKED(String, script_name, args[0]);
11938
11939 // Find the requested script.
11940 Handle<Object> result =
11941 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11942 return *result;
11943}
11944
11945
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011946// Determines whether the given stack frame should be displayed in
11947// a stack trace. The caller is the error constructor that asked
11948// for the stack trace to be collected. The first time a construct
11949// call to this function is encountered it is skipped. The seen_caller
11950// in/out parameter is used to remember if the caller has been seen
11951// yet.
11952static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
11953 bool* seen_caller) {
11954 // Only display JS frames.
11955 if (!raw_frame->is_java_script())
11956 return false;
11957 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
11958 Object* raw_fun = frame->function();
11959 // Not sure when this can happen but skip it just in case.
11960 if (!raw_fun->IsJSFunction())
11961 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011962 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011963 *seen_caller = true;
11964 return false;
11965 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011966 // Skip all frames until we've seen the caller. Also, skip the most
11967 // obvious builtin calls. Some builtin calls (such as Number.ADD
11968 // which is invoked using 'call') are very difficult to recognize
11969 // so we're leaving them in for now.
11970 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011971}
11972
11973
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011974// Collect the raw data for a stack trace. Returns an array of 4
11975// element segments each containing a receiver, function, code and
11976// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011977RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011978 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011979 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011980 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
11981
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011982 HandleScope scope(isolate);
11983 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011984
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000011985 limit = Max(limit, 0); // Ensure that limit is not negative.
11986 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011987 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011988 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011989
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011990 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011991 // If the caller parameter is a function we skip frames until we're
11992 // under it before starting to collect.
11993 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011994 int cursor = 0;
11995 int frames_seen = 0;
11996 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011997 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011998 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011999 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012000 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012001 // Set initial size to the maximum inlining level + 1 for the outermost
12002 // function.
12003 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012004 frame->Summarize(&frames);
12005 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012006 if (cursor + 4 > elements->length()) {
12007 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12008 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012009 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012010 for (int i = 0; i < cursor; i++) {
12011 new_elements->set(i, elements->get(i));
12012 }
12013 elements = new_elements;
12014 }
12015 ASSERT(cursor + 4 <= elements->length());
12016
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012017 Handle<Object> recv = frames[i].receiver();
12018 Handle<JSFunction> fun = frames[i].function();
12019 Handle<Code> code = frames[i].code();
12020 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012021 elements->set(cursor++, *recv);
12022 elements->set(cursor++, *fun);
12023 elements->set(cursor++, *code);
12024 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012025 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012026 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012027 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012028 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012029 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012030 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012031 return *result;
12032}
12033
12034
ager@chromium.org3811b432009-10-28 14:53:37 +000012035// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012036RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012037 ASSERT_EQ(args.length(), 0);
12038
12039 NoHandleAllocation ha;
12040
12041 const char* version_string = v8::V8::GetVersion();
12042
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012043 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12044 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012045}
12046
12047
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012048RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012049 ASSERT(args.length() == 2);
12050 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
12051 Smi::cast(args[1])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012052 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012053 OS::Abort();
12054 UNREACHABLE();
12055 return NULL;
12056}
12057
12058
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012059RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012060 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012061 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012062 Object* key = args[1];
12063
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012064 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012065 Object* o = cache->get(finger_index);
12066 if (o == key) {
12067 // The fastest case: hit the same place again.
12068 return cache->get(finger_index + 1);
12069 }
12070
12071 for (int i = finger_index - 2;
12072 i >= JSFunctionResultCache::kEntriesIndex;
12073 i -= 2) {
12074 o = cache->get(i);
12075 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012076 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012077 return cache->get(i + 1);
12078 }
12079 }
12080
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012081 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012082 ASSERT(size <= cache->length());
12083
12084 for (int i = size - 2; i > finger_index; i -= 2) {
12085 o = cache->get(i);
12086 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012087 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012088 return cache->get(i + 1);
12089 }
12090 }
12091
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012092 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012093 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012094
12095 Handle<JSFunctionResultCache> cache_handle(cache);
12096 Handle<Object> key_handle(key);
12097 Handle<Object> value;
12098 {
12099 Handle<JSFunction> factory(JSFunction::cast(
12100 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12101 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012102 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012103 // This handle is nor shared, nor used later, so it's safe.
12104 Object** argv[] = { key_handle.location() };
12105 bool pending_exception = false;
12106 value = Execution::Call(factory,
12107 receiver,
12108 1,
12109 argv,
12110 &pending_exception);
12111 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012112 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012113
12114#ifdef DEBUG
12115 cache_handle->JSFunctionResultCacheVerify();
12116#endif
12117
12118 // Function invocation may have cleared the cache. Reread all the data.
12119 finger_index = cache_handle->finger_index();
12120 size = cache_handle->size();
12121
12122 // If we have spare room, put new data into it, otherwise evict post finger
12123 // entry which is likely to be the least recently used.
12124 int index = -1;
12125 if (size < cache_handle->length()) {
12126 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12127 index = size;
12128 } else {
12129 index = finger_index + JSFunctionResultCache::kEntrySize;
12130 if (index == cache_handle->length()) {
12131 index = JSFunctionResultCache::kEntriesIndex;
12132 }
12133 }
12134
12135 ASSERT(index % 2 == 0);
12136 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12137 ASSERT(index < cache_handle->length());
12138
12139 cache_handle->set(index, *key_handle);
12140 cache_handle->set(index + 1, *value);
12141 cache_handle->set_finger_index(index);
12142
12143#ifdef DEBUG
12144 cache_handle->JSFunctionResultCacheVerify();
12145#endif
12146
12147 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012148}
12149
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012150
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012151RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012152 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012153 CONVERT_ARG_CHECKED(String, type, 0);
12154 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012155 return *isolate->factory()->NewJSMessageObject(
12156 type,
12157 arguments,
12158 0,
12159 0,
12160 isolate->factory()->undefined_value(),
12161 isolate->factory()->undefined_value(),
12162 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012163}
12164
12165
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012166RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012167 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12168 return message->type();
12169}
12170
12171
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012172RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012173 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12174 return message->arguments();
12175}
12176
12177
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012178RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012179 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12180 return Smi::FromInt(message->start_position());
12181}
12182
12183
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012184RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012185 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12186 return message->script();
12187}
12188
12189
kasper.lund44510672008-07-25 07:37:58 +000012190#ifdef DEBUG
12191// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12192// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012193RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012194 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012195 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012196#define COUNT_ENTRY(Name, argc, ressize) + 1
12197 int entry_count = 0
12198 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12199 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12200 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12201#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012202 Factory* factory = isolate->factory();
12203 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012204 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012205 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012206#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012207 { \
12208 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012209 Handle<String> name; \
12210 /* Inline runtime functions have an underscore in front of the name. */ \
12211 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012212 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012213 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12214 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012215 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012216 Vector<const char>(#Name, StrLength(#Name))); \
12217 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012218 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012219 pair_elements->set(0, *name); \
12220 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012221 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012222 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012223 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012224 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012225 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012226 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012227 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012228 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012229#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012230 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012231 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012232 return *result;
12233}
kasper.lund44510672008-07-25 07:37:58 +000012234#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012235
12236
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012237RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012238 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012239 CONVERT_CHECKED(String, format, args[0]);
12240 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012241 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012242 LOGGER->LogRuntime(chars, elms);
12243 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012244}
12245
12246
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012247RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012248 UNREACHABLE(); // implemented as macro in the parser
12249 return NULL;
12250}
12251
12252
12253// ----------------------------------------------------------------------------
12254// Implementation of Runtime
12255
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012256#define F(name, number_of_args, result_size) \
12257 { Runtime::k##name, Runtime::RUNTIME, #name, \
12258 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012259
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012260
12261#define I(name, number_of_args, result_size) \
12262 { Runtime::kInline##name, Runtime::INLINE, \
12263 "_" #name, NULL, number_of_args, result_size },
12264
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012265static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012266 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012267 INLINE_FUNCTION_LIST(I)
12268 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012269};
12270
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012271
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012272MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12273 Object* dictionary) {
12274 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012275 ASSERT(dictionary != NULL);
12276 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12277 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012278 Object* name_symbol;
12279 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012280 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012281 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12282 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012283 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012284 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12285 String::cast(name_symbol),
12286 Smi::FromInt(i),
12287 PropertyDetails(NONE, NORMAL));
12288 if (!maybe_dictionary->ToObject(&dictionary)) {
12289 // Non-recoverable failure. Calling code must restart heap
12290 // initialization.
12291 return maybe_dictionary;
12292 }
12293 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012294 }
12295 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012296}
12297
12298
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012299const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12300 Heap* heap = name->GetHeap();
12301 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012302 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012303 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012304 int function_index = Smi::cast(smi_index)->value();
12305 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012306 }
12307 return NULL;
12308}
12309
12310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012311const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012312 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12313}
12314
12315
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012316void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012317 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012318 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012319 if (failure->IsRetryAfterGC()) {
12320 // Try to do a garbage collection; ignore it if it fails. The C
12321 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012322 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012323 } else {
12324 // Handle last resort GC and make sure to allow future allocations
12325 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012326 isolate->counters()->gc_last_resort_from_js()->Increment();
12327 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012328 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012329}
12330
12331
12332} } // namespace v8::internal